每次我想在里面写字时,我都应该点击 NFC 标签吗?

Should I tap NFC tag every time I want to write in it?

我是 android 开发者

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

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

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

    }
}

还有另一种更好的方法来通知标签进入范围,尤其是当您正在写入标签时,这称为 enableReaderMode 但您的用例很奇怪。

我不确定为什么你会想要一个 NFC 标签贴在 phone 的背面,因为当文件在 phone ]的记忆力会好很多。

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

因此,即使在用户单击按钮时也可以执行您希望和写入(或读取)的操作,即使这很复杂。

你的App放到后台再拉到前台后,Tag对象是否可用,我没有测试过,但我觉得不太可能,因为后台App可能会关闭,关闭肯定无效Tag 对象。

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

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

  2. 你应该只在你不想再写的时候在标签上调用 close,在你写了一次之后调用 close .

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

使用 enableReaderMode 获得标签最初进入范围的通知,将标签对象存储在全局 Activity 范围中,并在 enableReaderMode 中将其 connect 一次=]回调线程。

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

切勿对标记对象调用关闭。

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