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 或不执行写入的情况下。

这可能是因为标签快速进入和超出范围时的时间问题,因为要传递有关标签第一次进入范围的信息,它必须 PauseResume您的应用程序可能需要一些时间,而在执行此操作时,您的应用程序在设计上已经 disableForegroundDispatch 正确,因此可能无法收到有关标签第二次进入范围的信息。

同时使用 enableForegroundDispatch 会导致人们在 UI 线程上执行标记 I/O,这违反了文档中的建议,并可能导致 I/O 被取消。

我并不是说这会解决您的问题,但我不会将旧的 enableForegroundDispatch API 用于 NFC,除非您真的需要支持非常非常旧的 Android 版本.

对于 API 19 岁及更高的年龄,我总是会使用较新的 enableReaderMode API。

enableReaderMode 不会暂停您的应用程序以接收数据,数据会在单独的线程中自动处理,因此不会导致 I/O 问题,您可以更好地控制声音,从而减少由于用户行为导致的错误,您可以解决某些硬件中轮询卡速度过快的错误。

的例子