【问题标题】:Should I tap NFC tag every time I want to write in it?每次我想写时都应该点击 NFC 标签吗?
【发布时间】:2021-07-28 22:15:54
【问题描述】:

我是一名安卓开发者

我有一个想法来开发一个在 NFC 标签数据上写入的应用程序。 (只写) 我有一个编辑文本和一个按钮,当我单击按钮时,我在 NFC 上写入了字段中写入的数据 我搜索了很多并尝试了几个代码 唯一的问题是我的 NFC 标签粘在手机背面,我使用的代码告诉我必须点击/标记 NFC 标签才能在其中写入 是否有其他方法可以检测点击按钮时贴在手机背面的 NFC 标签?

我有两个活动主要活动将从我的 NFCManager 调用方法 我将在NFCManager类下面分享 NFCManager 类:

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;

import java.io.ByteArrayOutputStream;
import java.util.Locale;

public class NFCManager {
    private Activity activity;
    private NfcAdapter nfcAdpt;

    public NFCManager(Activity activity) {
        this.activity = activity;
    }

    public void verifyNFC() throws NFCNotSupported, NFCNotEnabled {

        nfcAdpt = NfcAdapter.getDefaultAdapter(activity);

        if (nfcAdpt == null)
            throw new NFCNotSupported();

        if (!nfcAdpt.isEnabled())
            throw new NFCNotEnabled();

    }

    public void enableDispatch() {
        Intent nfcIntent = new Intent(activity, getClass());
        nfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(activity, 0, nfcIntent, 0);
        IntentFilter[] intentFiltersArray = new IntentFilter[] {};
        String[][] techList = new String[][] { { android.nfc.tech.Ndef.class.getName() }, { android.nfc.tech.NdefFormatable.class.getName() } };


        nfcAdpt.enableForegroundDispatch(activity, pendingIntent, intentFiltersArray, techList);
    }

    public void disableDispatch() {
        nfcAdpt.disableForegroundDispatch(activity);
    }

    public static class NFCNotSupported extends Exception {

        public NFCNotSupported() {
            super();
        }
    }

    public static class NFCNotEnabled extends Exception {

        public NFCNotEnabled() {
            super();
        }
    }


    public void writeTag(Tag tag, NdefMessage message)  {
        if (tag != null) {
            try {
                Ndef ndefTag = Ndef.get(tag);

                if (ndefTag == null) {
                    // Let's try to format the Tag in NDEF
                    NdefFormatable nForm = NdefFormatable.get(tag);
                    if (nForm != null) {
                        nForm.connect();
                        nForm.format(message);
                        nForm.close();
                    }
                }
                else {
                    ndefTag.connect();
                    ndefTag.writeNdefMessage(message);
                    ndefTag.close();
                }
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    public NdefMessage createUriMessage(String content, String type) {
        NdefRecord record = NdefRecord.createUri(type + content);
        NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
        return msg;

    }

    public NdefMessage createTextMessage(String content) {
        try {
            // Get UTF-8 byte
            byte[] lang = Locale.getDefault().getLanguage().getBytes("UTF-8");
            byte[] text = content.getBytes("UTF-8"); // Content in UTF-8

            int langSize = lang.length;
            int textLength = text.length;

            ByteArrayOutputStream payload = new ByteArrayOutputStream(1 + langSize + textLength);
            payload.write((byte) (langSize & 0x1F));
            payload.write(lang, 0, langSize);
            payload.write(text, 0, textLength);
            NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload.toByteArray());
            return new NdefMessage(new NdefRecord[]{record});
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public NdefMessage createExternalMessage(String content) {
        NdefRecord externalRecord = NdefRecord.createExternal("com.survivingwithandroid", "data", content.getBytes());

        NdefMessage ndefMessage = new NdefMessage(new NdefRecord[] { externalRecord });

        return ndefMessage;
    }
}

我的 MainActivity 中的方法:

@Override
protected void onResume() {
    super.onResume();

    try {
        nfcMger.verifyNFC();
        //nfcMger.enableDispatch();

        Intent nfcIntent = new Intent(this, getClass());
        nfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, nfcIntent, 0);
        IntentFilter[] intentFiltersArray = new IntentFilter[] {};
        String[][] techList = new String[][] { { android.nfc.tech.Ndef.class.getName() }, { android.nfc.tech.NdefFormatable.class.getName() } };
        NfcAdapter nfcAdpt = NfcAdapter.getDefaultAdapter(this);
        nfcAdpt.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techList);
    }
    catch(NFCManager.NFCNotSupported nfcnsup) {
        Snackbar.make(v, "NFC not supported", Snackbar.LENGTH_LONG).show();
    }
    catch(NFCManager.NFCNotEnabled nfcnEn) {
        Snackbar.make(v, "NFC Not enabled", Snackbar.LENGTH_LONG).show();
    }

}


@Override
protected void onPause() {
    super.onPause();
    nfcMger.disableDispatch();
}

@Override
public void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    Log.d("Nfc", "New intent");
    // It is the time to write the tag
    currentTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    if (message != null) {
        nfcMger.writeTag(currentTag, message);
        dialog.dismiss();
        Snackbar.make(v, "Tag written", Snackbar.LENGTH_LONG).show();

    } else {
        // Handle intent

    }
}

【问题讨论】:

    标签: java android nfc mobile-development


    【解决方案1】:

    还有另一种更好的方法来获得标签进入范围的通知,特别是如果您正在写入标签,这称为enableReaderMode,但您的用例很奇怪。

    我不知道你为什么要在手机背面贴一个 NFC 标签,因为当手机内存上的文件会好得多时,它会像非常慢和小尺寸的永久存储一样。

    请记住,一旦标签进入范围,您就会通过enableForegroundDispatchenableReaderMode 通知标签已进入范围并获得一个标签对象。只要该 Tag 没有超出范围,并且您已将 Tag 对象存储在 Activity 的全局范围内,那么您可以随意多次写入它,只要您愿意。

    因此,即使用户单击按钮,也应该可以执行您想要和写入(或读取)的操作,如果很复杂的话。

    我还没有测试过在你的应用程序被放到后台并再次被带到前台之后标签对象是否可用,但我认为这不太可能,因为后台应用程序可能被关闭并且关闭肯定会使标签无效对象。

    但是你的代码有两个问题。

    1. 真正调用 connectwrite 到您的 Tag 永远不应该在 UI 线程上完成,因为它是 IO 阻塞并且可能被取消,这会导致 Tag 超出范围并再次回到范围内.幸运的是,如果您使用 enableReaderMode,那么您会在单独的线程中收到通知。

    2. 您应该只在您不想再写时在标签上调用close,此时您在写过一次之后才调用close

    因此,以下内容可能对您有用,但限制是标签必须在应用程序启动后第一次进入范围。

    使用enableReaderMode 得到通知,标签最初进入范围,将标签对象存储在全局活动范围中,并在enableReaderMode 回调线程中将connect 存储一次。

    当按钮被按下时,从 UI 开始一个新的线程到write 到标签。

    永远不要在标签对象上调用 close。

    请注意,我没有对此进行测试,因为这是一个非常奇怪的用例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多