Nfc Pending Intent 在某些情况下未交付
Nfc Pending Intent not getting delivered on some situation
我的应用程序的一些用户抱怨 NFC 在同一个 NFC 标签上始终无法正常工作。有时从设置中重置 NFC 选项可以解决问题。
我们有 HomeActivity
接收 NFC 意图并将其传送到所需的片段。这是我尝试过的。
片段面:
override fun onResume() {
super.onResume()
enableNFCForegroundDispatch()
....
}
override fun onPause() {
mNfcAdapter?.disableForegroundDispatch(requireActivity())
super.onPause()
...
}
private fun enableNFCForegroundDispatch() {
if (mNfcAdapter == null) {
mNfcAdapter =
(requireActivity().getSystemService(AppCompatActivity.NFC_SERVICE) as NfcManager).defaultAdapter
}
val intent = HomeActivity.newIntent(requireContext())
val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE
} else 0
val pi = PendingIntent.getActivity(requireContext(), PENDING_INTENT_TECH_DISCOVERED, intent, flag)
if (pi != null) {
mNfcAdapter?.enableForegroundDispatch(
requireActivity(),
pi,
arrayOf(
IntentFilter(
NfcAdapter.ACTION_TECH_DISCOVERED
)
),
arrayOf(arrayOf("android.nfc.tech.NfcV"))
)
}
}
override fun onNewIntent(intent: Intent?) {
// just an implementation by all fragments to handle new intent from the parent
// we don't get this in the error cases
Timber.tag(SENSOR).d("NFC onNewIntent: intent received ${intent?.action} ${intent?.data}")
when (intent?.action) {
NfcAdapter.ACTION_TECH_DISCOVERED -> {
Timber.tag(SENSOR).d("NFC onNewIntent: nfc intent received")
resolveIntent(intent)
}
}
}
Activity 边:
companion object {
fun newIntent(context: Context): Intent {
val intent = Intent(context, HomeActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
return intent
}
}
清单:
<activity
android:name=".home.HomeActivity"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/UiSdkTheme.NoActionBar.NoNavigationBar">
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
</activity>
nfc_tech_filter:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.NfcV</tech>
</tech-list>
</resources>
我发现使用旧的基于 Intent 的方法来读取标签非常不可靠,尤其是在不执行 Ndef 或不执行写入的情况下。
这可能是因为标签快速进入和超出范围时的时间问题,因为要传递有关标签第一次进入范围的信息,它必须 Pause
和 Resume
您的应用程序可能需要一些时间,而在执行此操作时,您的应用程序在设计上已经 disableForegroundDispatch
正确,因此可能无法收到有关标签第二次进入范围的信息。
同时使用 enableForegroundDispatch
会导致人们在 UI 线程上执行标记 I/O,这违反了文档中的建议,并可能导致 I/O 被取消。
我并不是说这会解决您的问题,但我不会将旧的 enableForegroundDispatch
API 用于 NFC,除非您真的需要支持非常非常旧的 Android 版本.
对于 API 19 岁及更高的年龄,我总是会使用较新的 enableReaderMode API。
enableReaderMode
不会暂停您的应用程序以接收数据,数据会在单独的线程中自动处理,因此不会导致 I/O 问题,您可以更好地控制声音,从而减少由于用户行为导致的错误,您可以解决某些硬件中轮询卡速度过快的错误。
的例子
我的应用程序的一些用户抱怨 NFC 在同一个 NFC 标签上始终无法正常工作。有时从设置中重置 NFC 选项可以解决问题。
我们有 HomeActivity
接收 NFC 意图并将其传送到所需的片段。这是我尝试过的。
片段面:
override fun onResume() {
super.onResume()
enableNFCForegroundDispatch()
....
}
override fun onPause() {
mNfcAdapter?.disableForegroundDispatch(requireActivity())
super.onPause()
...
}
private fun enableNFCForegroundDispatch() {
if (mNfcAdapter == null) {
mNfcAdapter =
(requireActivity().getSystemService(AppCompatActivity.NFC_SERVICE) as NfcManager).defaultAdapter
}
val intent = HomeActivity.newIntent(requireContext())
val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE
} else 0
val pi = PendingIntent.getActivity(requireContext(), PENDING_INTENT_TECH_DISCOVERED, intent, flag)
if (pi != null) {
mNfcAdapter?.enableForegroundDispatch(
requireActivity(),
pi,
arrayOf(
IntentFilter(
NfcAdapter.ACTION_TECH_DISCOVERED
)
),
arrayOf(arrayOf("android.nfc.tech.NfcV"))
)
}
}
override fun onNewIntent(intent: Intent?) {
// just an implementation by all fragments to handle new intent from the parent
// we don't get this in the error cases
Timber.tag(SENSOR).d("NFC onNewIntent: intent received ${intent?.action} ${intent?.data}")
when (intent?.action) {
NfcAdapter.ACTION_TECH_DISCOVERED -> {
Timber.tag(SENSOR).d("NFC onNewIntent: nfc intent received")
resolveIntent(intent)
}
}
}
Activity 边:
companion object {
fun newIntent(context: Context): Intent {
val intent = Intent(context, HomeActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
return intent
}
}
清单:
<activity
android:name=".home.HomeActivity"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/UiSdkTheme.NoActionBar.NoNavigationBar">
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
</activity>
nfc_tech_filter:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.NfcV</tech>
</tech-list>
</resources>
我发现使用旧的基于 Intent 的方法来读取标签非常不可靠,尤其是在不执行 Ndef 或不执行写入的情况下。
这可能是因为标签快速进入和超出范围时的时间问题,因为要传递有关标签第一次进入范围的信息,它必须 Pause
和 Resume
您的应用程序可能需要一些时间,而在执行此操作时,您的应用程序在设计上已经 disableForegroundDispatch
正确,因此可能无法收到有关标签第二次进入范围的信息。
同时使用 enableForegroundDispatch
会导致人们在 UI 线程上执行标记 I/O,这违反了文档中的建议,并可能导致 I/O 被取消。
我并不是说这会解决您的问题,但我不会将旧的 enableForegroundDispatch
API 用于 NFC,除非您真的需要支持非常非常旧的 Android 版本.
对于 API 19 岁及更高的年龄,我总是会使用较新的 enableReaderMode API。
enableReaderMode
不会暂停您的应用程序以接收数据,数据会在单独的线程中自动处理,因此不会导致 I/O 问题,您可以更好地控制声音,从而减少由于用户行为导致的错误,您可以解决某些硬件中轮询卡速度过快的错误。