How To: NFC Part 1: Scanning an NDEF-formatted NFC Tag

In this article we’ll be discussing how to read data from an NDEF-formatted NFC Tag in an Android app.

In case you aren’t aware, NDEF is a format (think NTFS or FAT). Android has simple, easy-to-use support for NDEF, so there’s no need for hacky methods to use it. If you are designing your project with NFC in mind, stick to NDEF as your formatting. All decent manufacturer’s support NDEF formatting, and so does your platform. Stick to it. Save the headache.

Requirements

  1. NFC  – this should go without saying
  2. API Level 10 – Android 2.3.3.

First, you must know that reading NFC tags is handled by an `Intent`. This allows any capable app of filtering the `Intent` and reacting appropriately. Now onto the good stuff.

Assuming that you’ve already created your project, create a new `Activity` (or use a pre-existing one, it doesn’t matter). The first step is to create an `IntentFilter` in your manifest.  By adding it to your manifest, this tells the system that your app is able to handle reading an NFC tag whether or not it is running. To reiterate, that means that your app doesn’t need to be running in the foreground, or even in the background; the system handles all this for you. Of course, this may not always be the case.

If you happen to need it to only accept it at run-time (e.g. only the currently running `Activity` should handle the` Intent`), you can always have the `Activity` register the Intent Filter in `onResume()` and unregister in `onPause()`. The details of this are not covered in this article.

Now for the `IntentFilter`, you need to add 3 things:

  1. The Action: `android.nfc.action.NDEF_DISCOVERED` – This means that an NDEF-formatted tag has been discovered.
  2. The Category: `android.intent.category.DEFAULT` – This means that your application can accept implicit intents which can then start your `Activity`.
  3. The Data – for our case, we’re going to use a custom MIME-type to carry the payload. It is good practice to use the MIME-type `application/my.package.name.MyActivity` so that it should be unique to your own app, and specific to the `Activity`. This will prevent accidentally having another app handle your `Intent`, and vice-versa.
For more information on Intents and Intent Filters see the Android Guide.
And now for the actual code:
<activity android:name=".MyActivity" >
    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="application/com.faizvisram.MyActivity"/>
    </intent-filter>
</activity>

See, simple.

What we’ve done so far is tell the system that we want to handle the `Intent` for all NDEF discoveries where the data is of MIME-type `com.faizvisram.MyActivity`. Don’t actually use my name though, or even this scheme. Use your own package name for consistency rather than random text. It’s good practice and it keeps your project clean, organised, and consistent.

Now that our `Activity` is notified that we can handle the `Intent`, we need our application to actually handle it. Right now it may just launch your `Activity`, but you probably want it to do more. This is even easier.

In `MyActivity`, you need to first check what `Intent` launched your `Activity`. We will do this in `onResume()` because by this point your `Activity` and it’s UI elements have just finished loading, so you may now influence your UI. We’re just going to check if the `Intent` is `android.nfc.action.NDEF_DISCOVERED` and do what we need done if it is.

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

	Intent intent = getIntent();

	// Check to see that the Activity started due to NDEF_DISCOVERED
	if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
            ndefDiscovered(intent);
	}
}

You may have noticed that I’ve passed `intent` as a parameter. This is just to prevent multiple calls to `getIntent()`.

Now we need to parse the payload in `ndefDiscovered(Intent)`.

private void processBeamIntent(Intent intent) {
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        // You should only get one message from an NFC tag
        NdefMessage msg = (NdefMessage) rawMsgs[0];
        // Record 0 contains the MIME-type payload
        String payload = new String(msg.getRecords()[0].getPayload());
}

Done and done! Well not really, you still need to do something with `payload`, but this tutorial is now done. You can display the text in a `TextView`, or do actions based on constants, or whatever you’d like. It’s really up to what your app needs to do with the data. Hell, it doesn’t even need to be parsed into a `String`, but I just did that to show how to make it usable.

Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *