NFC tag has UID/serial number but getByteArrayExtra returns null

2k views Asked by At

I am working on an app that is in its final stages when I was asked to make changes to it to read the unique serial number of NFC tags. No big problem there, however in the case of some of the tags the serial number is returned as null.

When using the NFC Tools app to inspect the tag the serial number is there but intent.getByteArrayExtra() method called with NfcAdapter.EXTRA_ID as parameter returns null in the case of those tags.

Below you have my Android manifest and the code I used to get the UID if it helps.

@Override
protected String doInBackground(Tag... params) {
    Tag tag = params[0];

    // New code to deal with multiple tag versions (supports NfcA, NDEF, MifareUltralight)

    // parse tech list
    byte[] uid = getIntent().getByteArrayExtra(NfcAdapter.EXTRA_ID);

    String serialNumber = uidByteToHexString(uid);

    if (serialNumber != null && !serialNumber.isEmpty()) {
        return serialNumber;
    }

Android Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="myPackageName here" >

    <!-- Application permissions go here, mainly NFC -->
    <uses-permission android:name="android.permission.NFC" />
    <users-feature android:name="android.hardware.nfc" android:required="true"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MyActivityNameHere"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/app_name"
            android:theme="@style/FullscreenTheme" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <!-- NFC Intent Filters -->
            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>

            <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />
        </activity>
    </application>

</manifest>

My other question is: When reading tags some tags trigger the chooser dialog making me choose which application do I want to use to process the tag. Would it be possible to eliminate that and have just my app deal with NFC events while it is active?

The tags I am using are NfcA, MifareUltralight and Ndef. If it helps.

1

There are 1 answers

0
Michael Roland On BEST ANSWER

When getIntent().getByteArrayExtra(NfcAdapter.EXTRA_ID) returns null, this means that getIntent() is not an NFC intent. Given the manifest that you posted (and assuming that the above code is used in MyActivityNameHere), this means that getIntent() gives you either a launcher intent (action MAIN with category LAUNCHER) or an explicit intent).

Typically, this could have two reasons:

  • Your activity was started by clicking its launcher icon (or from another activity/component). You later scanned an NFC tag and that event was delivered through the onNewIntent() method (e.g. because you registered for the foreground dispatch system) but you did not update the activity's intent field with setIntent(). In that case, getIntent() would still return the intent that initially started the activity and not the NFC intent that you received later on.

  • The NFC tag contains an Android Application Record (AAR) but its first record is not a text/plain record. As your NDEF_DISCOVERED intent filter requires a text/plain NDEF record as first record, Android does not know that your activity supports that type of tag and consequently starts your app using a MAIN+LAUNCHER intent instead of an NFC intent. Therefore, this intent will neither contain the tag ID nor a handle to the tag.

You can check the type of the intent with intent.getAction(). For an NFC intent, this would return one of

  • android.nfc.action.NDEF_DISCOVERED,
  • android.nfc.action.TECH_DISCOVERED, or
  • android.nfc.action.TAG_DISCOVERED.

Regarding the intent chooser dialog, I suggest that you read through How NFC Tags are Dispatched to Applications. This document thouroughly explains how applications get priority for NFC intents.