检测到 NFC 标签时显示 toast 消息

Display toast message when NFC tag is detected

我一点也不熟悉 NFC 标签检测,我正在尝试为 activity 中检测到的任何 NFC 标签设置一个侦听器。我只想在 activity 检测到 NFC 标签时显示提示消息,但我在这样做时遇到了问题。

MainActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity)

    val nfcAdapter = NfcAdapter.getDefaultAdapter(this)

}

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)

    Toast.makeText(applicationContext, "NFC Tag Detected", Toast.LENGTH_LONG).show()

}

在我的清单中我有这个:

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <action android:name="android.nfc.action.TECH_DISCOVERED" />
    <action android:name="android.nfc.action.TAG_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

我正在使用 Samsung Galaxy S6 和 S7 对此进行测试。当我将它们放在一起而其中一个上的 activity 是 运行 时,我希望能够看到祝酒消息,但到目前为止没有任何显示。我不需要读取标签,我不关心它是什么类型的标签,我只需要知道检测到标签。

您在应用清单中注册的 Intent 过滤器没有多大意义。

  • android.nfc.action.TAG_DISCOVERED(在清单中使用时)只是一种后备机制,用于捕获其他应用程序未处理的任何 NFC 标签。
  • android.nfc.action.NDEF_DISCOVERED 还需要一个数据类型规范来实际捕获包含 特定 NDEF 记录的 NFC 标签。它不会匹配没有标签的任何标签。
  • android.nfc.action.TECH_DISCOVERED 还需要一个技术来捕捉特定的标签技术。它不会匹配没有标签的任何标签。

此外,您可能希望将每个意图操作放在一个单独的 <intent-filter> 中,以便更好地控制类别、数据类型等。

但是,由于您只对在 activity 处于前台时接收 NFC 发现事件感兴趣,因此您有更好且(某种程度上)更可靠的选项来检测标签:前台调度系统和 reader模式API.

你想在其中之一中选择:

  • 如果您使用的是 Android 4.4+,并且您只对检测其他标签感兴趣( 点对点模式设备)。我强烈建议您使用 reader 模式 API 因为它可以让您更好地控制要检测的标签以及应如何处理这些标签。此外,如果您希望能够检测到另一个 Android 设备上的 HCE 应用程序并与其通信,您唯一的选择是 reader 模式 API.
  • 如果您还想支持 Android 4.4 之前的设备,或者如果您还想从点对点设备接收数据(例如通过 Android Beam),您需要坚持到前台调度系统。

前台调度系统

您可以注册 activity 以在 onResume() 期间接收 NFC intent:

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

    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
}

在 Kotlin 中可能是这样的(虽然没有测试):

fun onResume() {
    super.onResume()
    val pendingIntent = PendingIntent.getActivity(this, 0, Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
    val nfcAdapter = NfcAdapter.getDefaultAdapter(this)
    nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null)
}

确保在 onPause() 期间再次取消注册:

@Override
public void onPause() {
    super.onPause();
    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    nfcAdapter.disableForegroundDispatch(this);
}

科特林:

fun onPause() {
    super.onPause()
    val nfcAdapter = NfcAdapter.getDefaultAdapter(this)
    nfcAdapter.disableForegroundDispatch(this)
}

然后您将通过 onNewIntent():

TAG_DISCOVERED 意图接收 NFC 事件
@Override
public void onNewIntent(Intent intent) {
    if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
        // TODO: process intent
    }
}

科特林:

fun onNewIntent(intent: Intent) {
    if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
        // TODO: process intent
    }
}

Reader模式API

使用 reader 模式 API,您在 onStart() 期间注册 activity 以接收 NFC 回调(此处未使用意图!):

@Override
public void onStart() {
    super.onStart();

    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    nfcAdapter.enableReaderMode(this, new NfcAdapter.ReaderCallback() {
        @Override
        public void onTagDiscovered(Tag tag) {
            // TODO: use NFC tag
        }
    }, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_NFC_B | NfcAdapter.FLAG_READER_NFC_F | NfcAdapter.FLAG_READER_NFC_V | NfcAdapter.FLAG_READER_NFC_BARCODE, null);
}

科特林:

fun onStart() {
    super.onStart()
    val nfcAdapter = NfcAdapter.getDefaultAdapter(this)
    nfcAdapter.enableReaderMode(this, object : NfcAdapter.ReaderCallback() {
        fun onTagDiscovered(tag: Tag) {
            // TODO: use NFC tag
        }
    }, NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_NFC_B or NfcAdapter.FLAG_READER_NFC_F or NfcAdapter.FLAG_READER_NFC_V or NfcAdapter.FLAG_READER_NFC_BARCODE, null)
}

您还应确保在 onStop():

期间取消注册
@Override
public void onStop() {
    super.onStop();
    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    nfcAdapter.disableReaderMode(this);
}

科特林:

fun onStop() {
    super.onStop()
    val nfcAdapter = NfcAdapter.getDefaultAdapter(this)
    nfcAdapter.disableReaderMode(this)
}

您通过上面的 onTagDiscovered(Tag tag) 回调方法接收发现的标签句柄。相反,当然,您也可以在 activity class 上实现 NfcAdapter.ReaderCallback 接口,并将 this 而不是匿名 class 传递给 enableReaderMode方法。