Connection error when reading Android NFC IsoDep tags
Asked Answered
E

2

8

I have an app that reads various types of NFC tag. 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. The tag in question has support for both Mifare Classic and ISO-DEP, but we're connecting using the IsoDep technology specifically.

Neither the NFC TagInfo or NFC TagInfo by NXP apps are able to read the tag without error either.


Devices that work:

  • Moto X Play (Android 6.0.1)
  • Moto G Play (Android 6.0.1)
  • Samsung Galaxy S7 (Android 7.0)
  • Samsung Galaxy S8 - UK model (Android 7.0)
  • Pixel 2 (Android 8.1)

Devices that fail:

  • Moto G5S (Android 7.1.1)
  • Moto Z2 Play (Android 7.1.1)
  • Moto E4 Plus (Android 7.1.1)
  • Huawei Honor 8 (Android 7.0)
  • LG K8 (Android 7.0)
  • LG K10 (Android 7.0)
  • Samsung Galaxy S8 - US model (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):

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).

Interestingly, for the devices that work, the tech list exposed by the Tag is as follows: 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

Finally, for devices that don't work, the following entry crops up in 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?

Electromotive answered 22/2, 2018 at 11:18 Comment(4)
Did you find any workaround of the problem?Mikimikihisa
@Mikimikihisa yes we did. We exhausted all avenues with code in the Android app and had to find a workaround. I wasn't privy to the details, but the solution was to simplify the NFC tag by removing one of the technology types such that the app didn't need to make any decisions about which one to use. I can try and get more specific information if needs be.Electromotive
@Electromotive can you provide more details?Cressy
I'm afraid not. I left the organisation some time ago, and at the time wasn't actively engaged with the fix on the NFC side. Sorry.Electromotive
A
0

I was seeing a similar issue with the IsoDep class when testing on Android 8+ vs Android 6,7

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.

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);
}
Abram answered 12/11, 2019 at 1:55 Comment(0)
R
0

When a Tag supports multiple technology entries, each entry can be independently accessed using basic Tag technology 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.

Raddy answered 12/5, 2021 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.