问题描述
我的应用使用前台调度系统来允许用户点击他们的 NFC 标签,以便在标签上执行读写操作.
如果用户正确点击他们的标签(即,他们在手机上的正确位置点击标签并保持连接足够长的时间),它会很好地工作,但如果他们过早物理删除标签,那么 ndef.writeNdefMessage(...)
抛出 IOException.
这意味着写操作失败,这很公平.但真正的问题是,同样的失败操作也会删除标签中的整个 ndef 格式/消息!
我的代码是围绕 Advanced NFC |Android 开发人员 页面(不幸的是 指向 ForegroundDispatch 示例的链接 似乎已损坏,并且没有此类示例项目可导入 Android Studio).
第 1 步.这是用户第一次点击其 NFC 标签但过早将其移开时的 logcat/stacktrace 输出:
03-28 20:15:18.589 21278-21278/com.example.exampleapp E/NfcTestActivity: 标记错误java.io.IOException在 android.nfc.tech.Ndef.writeNdefMessage(Ndef.java:320)在 com.example.exampleapp.NfcTestActivity.onNewIntent(NfcTestActivity.java:170)在 android.app.Instrumentation.callActivityOnNewIntent(Instrumentation.java:1224)在 android.app.ActivityThread.deliverNewIntents(ActivityThread.java:2946)在 android.app.ActivityThread.performNewIntents(ActivityThread.java:2959)在 android.app.ActivityThread.handleNewIntent(ActivityThread.java:2968)在 android.app.ActivityThread.access$1700(ActivityThread.java:181)在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1554)在 android.os.Handler.dispatchMessage(Handler.java:102)在 android.os.Looper.loop(Looper.java:145)在 android.app.ActivityThread.main(ActivityThread.java:6145)在 java.lang.reflect.Method.invoke(本机方法)在 java.lang.reflect.Method.invoke(Method.java:372)在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)03-28 20:15:18.599 1481-17792/?E/SecNfcJni:nfaConnectionCallback:NFA_SELECT_RESULT_EVT 错误:状态 = 303-28 20:15:18.599 1481-1502/?E/SecNfcJni:重新选择:标签未激活
第 2 步. 接下来,同一用户再次点击同一标签,但它似乎不再包含 ndef 消息(我已通过更改代码并检查 ndef.getCachedNdefMessage()
返回 null
):
03-28 20:15:27.499 21278-21278/com.example.exampleapp E/NfcTestActivity: 标记错误java.lang.Exception:标签不是 ndef 格式:android.nfc.action.TECH_DISCOVERED在 com.example.exampleapp.NfcTestActivity.onNewIntent(NfcTestActivity.java:124)在 android.app.Instrumentation.callActivityOnNewIntent(Instrumentation.java:1224)在 android.app.ActivityThread.deliverNewIntents(ActivityThread.java:2946)在 android.app.ActivityThread.performNewIntents(ActivityThread.java:2959)在 android.app.ActivityThread.handleNewIntent(ActivityThread.java:2968)在 android.app.ActivityThread.access$1700(ActivityThread.java:181)在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1554)在 android.os.Handler.dispatchMessage(Handler.java:102)在 android.os.Looper.loop(Looper.java:145)在 android.app.ActivityThread.main(ActivityThread.java:6145)在 java.lang.reflect.Method.invoke(本机方法)在 java.lang.reflect.Method.invoke(Method.java:372)在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
到目前为止,我在测试过的两台设备上都遇到了这个问题——运行 Android 5.1.1 的 Samsung Galaxy Core Prime(低端手机)和 Samsung Galaxy A5(中端手机)运行 Android 5.0.2.
我的应用程序使用的 NFC 标签包含重要信息(即,不能无意中删除标签数据!),所以我的问题是......
- 为什么我的代码(见下文)会这样擦除标签数据?
- 如何解决根本问题,或者是否有可接受的解决方法?
- 是否值得我尝试使用 NfcA 或 IsoDep 而不是 Ndef?
做了很多搜索后,我很惊讶这个问题没有在其他地方讨论过,所以如果问题与我的代码无关,那么可能与我正在使用的 NFC 标签有关?...
我使用的标签是 NXP MIFARE Ultralight (Ultralight C) - NTAG203(标签类型:ISO 14443-3A).其中一些是我从 ebay 购买的,还有一些是从 Rapid NFC(一家有信誉的公司)购买的,但我似乎都遇到了这个问题.
这是我的完整活动代码:
包 com.example.exampleapp;导入 android.app.PendingIntent;导入android.content.Intent;导入 android.content.IntentFilter;导入android.nfc.NdefMessage;导入android.nfc.NdefRecord;导入 android.nfc.NfcAdapter;导入android.nfc.Tag;导入android.nfc.tech.Ndef;导入android.os.Bundle;导入android.os.Handler;导入android.os.Looper;导入android.support.v7.app.AppCompatActivity;导入android.util.Log;导入 android.widget.Toast;公共类 NfcTestActivity 扩展 AppCompatActivity {私有静态字符串 LOG_TAG = NfcTestActivity.class.getSimpleName();私有静态 int SUCCESS_COUNT = 0;私有静态 int FAILURE_COUNT = 0;私有 NfcAdapter nfcAdapter;私有的 PendingIntent私有 IntentFilter[] intentFiltersArray;私有字符串[][] techListsArray;@覆盖protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_nfc_test);getSupportActionBar().setDisplayShowHomeEnabled(true);nfcAdapter = NfcAdapter.getDefaultAdapter(this);如果(nfcAdapter == null){makeToast("NFC 不可用!", Toast.LENGTH_LONG);结束();}别的 {//makeToast("NFC 可用");pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);尝试 {ndef.addDataType("*/*");/* 处理所有基于 MIME 的调度.您应该只指定您需要的那些.*