简体   繁体   English

读取 Android NFC IsoDep 标签时出现连接错误

[英]Connection error when reading Android NFC IsoDep tags

I have an app that reads various types of NFC tag.我有一个应用程序可以读取各种类型的 NFC 标签。 For years it's worked fine, but with newer Android devices a java.io.IOException is thrown consistently when scanning a particular type of tag.多年来它一直运行良好,但对于较新的 Android 设备,在扫描特定类型的标签时会持续抛出java.io.IOException The tag in question has support for both Mifare Classic and ISO-DEP, but we're connecting using the IsoDep technology specifically.有问题的标签同时支持 Mifare Classic 和 ISO-DEP,但我们专门使用IsoDep技术进行连接。

Neither the NFC TagInfo or NFC TagInfo by NXP apps are able to read the tag without error either. NXP应用程序的NFC TagInfoNFC TagInfo都无法正确读取标签。


Devices that work:工作的设备:

  • Moto X Play (Android 6.0.1) Moto X Play (Android 6.0.1)
  • Moto G Play (Android 6.0.1) Moto G Play (Android 6.0.1)
  • Samsung Galaxy S7 (Android 7.0)三星 Galaxy S7(安卓 7.0)
  • Samsung Galaxy S8 - UK model (Android 7.0)三星 Galaxy S8 - 英国型号(Android 7.0)
  • Pixel 2 (Android 8.1)像素 2(安卓 8.1)

Devices that fail:失败的设备:

  • Moto G5S (Android 7.1.1)摩托 G5S(安卓 7.1.1)
  • Moto Z2 Play (Android 7.1.1) Moto Z2 Play (Android 7.1.1)
  • Moto E4 Plus (Android 7.1.1) Moto E4 Plus (Android 7.1.1)
  • Huawei Honor 8 (Android 7.0)华为荣耀8(安卓7.0)
  • LG K8 (Android 7.0) LG K8 (Android 7.0)
  • LG K10 (Android 7.0) LG K10 (Android 7.0)
  • Samsung Galaxy S8 - US model (Android 7.0)三星 Galaxy S8 - 美国型号(Android 7.0)

The code needed to repro the issue is dead simple.重现问题所需的代码非常简单。

The NFC intent is received through foreground dispatch, and the following then runs in its own thread (with no other threads or NFC-related processing in between):通过前台调度接收 NFC 意图,然后在其自己的线程中运行以下内容(中间没有其他线程或 NFC 相关处理):

IsoDep isoDep = IsoDep.get(tag);

try {
    isoDep.connect();
}
catch (IOException e) {
    Log.e("NFC", ":(");
}

When the IOException is thrown by the connect() method within android.nfc.tech.BasicTagTechnology , the errorCode is -5 (ERROR_CONNECT).android.nfc.tech.BasicTagTechnologyconnect()方法抛出IOExceptionerrorCode为 -5 (ERROR_CONNECT)。

Interestingly, for the devices that work, the tech list exposed by the Tag is as follows: android.nfc.tech.IsoDep, android.nfc.tech.NfcA有趣的是,对于可以工作的设备, Tag暴露的技术列表如下: android.nfc.tech.IsoDep, android.nfc.tech.NfcA

For devices that don't work the tech list is much longer, and contains duplicates: android.nfc.tech.IsoDep, android.nfc.tech.NfcA, android.nfc.tech.NfcA, android.nfc.tech.MifareClassic, android.nfc.tech.NdefFormattable对于不工作的设备,技术列表更长,并且包含重复项: android.nfc.tech.IsoDep、android.nfc.tech.NfcA、android.nfc.tech.NfcA、android.nfc.tech.MifareClassic、 android.nfc.tech.NdefFormattable

Finally, for devices that don't work, the following entry crops up in logcat: E/NxpNfcJni: Mifare Classic detected最后,对于不工作的设备,logcat 中会出现以下条目: E/NxpNfcJni: Mifare Classic detected

Is it possible that with the extended NFC support offered by the more modern Android devices there is some confusion within the NFC system service about what TagTechnology to connect to?是否有可能通过更现代的 Android 设备提供的扩展 NFC 支持,NFC 系统服务中关于要连接到什么 TagTechnology 存在一些混淆?

I was seeing a similar issue with the IsoDep class when testing on Android 8+ vs Android 6,7在 Android 8+ 与 Android 6,7 上进行测试时,我发现IsoDep类存在类似问题

The key for me was to make use of the NfcAdapter.enableReaderMode instance method to turn off Host-Card-Emulation on the Android-Device while my App was in the foreground and trying to Read/Write Tags.我的关键是利用NfcAdapter.enableReaderMode实例方法在我的应用程序处于前台并尝试读取/写入标签时关闭 Android 设备上的主机卡模拟

Then instead of applying the lifecycle callbacks as shown the Documentation Example , I followed the advice as noted for this Question and did the following;然后,我没有按照文档示例中所示应用生命周期回调,而是按照此问题所述的建议进行了以下操作;

@Override
public void onPause() {
    super.onPause();
    NfcAdapter.getDefaultAdapter(this).disableReaderMode(this);
}

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

    Bundle options = new Bundle();
    options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 500);

    adapter.enableReaderMode(
        this,
        new NfcAdapter.ReaderCallback() {
             @Override
             public void onTagDiscovered(final Tag tag) {
                 IsoDep isoDep = IsoDep.get(tag);
                 // Connect and perform rest of communication
             }
        },
        NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK,
        options
    ); 
}

@Override
public void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
}

When a Tag supports multiple technology entries, each entry can be independently accessed using basic Tag technology api - tag.getTechList( );当一个 Tag 支持多个技术条目时,可以使用基本的 Tag 技术 api - tag.getTechList() 独立访问每个条目;

Modify your code as follows:修改你的代码如下:

    techList =  tag.getTechList();
    for (String tech : techList) {
        if (tech.equals("android.nfc.tech.IsoDep")) 
        {
            Log.i(TAG, "Tag Tech ISO DEP Found: " + tech );
            IsoDep isoDep = IsoDep.get(tag);
            try 
            {
                    isoDep.connect();
            }
            catch (IOException e) 
            {
                Log.e("NFC", ":(");
            }
        }
    }

Not all device will support MifareClassic Tag technology.并非所有设备都支持 MifareClassic Tag 技术。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM