Fun with Android and NFC

So, you probably heard of something called NFC (Near Field Communication), and maybe you have seen the video (as shown below) from the 2012 Google I/O showing you a developers perspective on NFC.

But what you want is a short “How to” on creating an Android NFC application. In this tutorial we’re going to build an app that reads and writes to an NFC tag.
In order to follow along you will need an NFC enabled Android device, such as the Samsung Galaxy Nexus or Samsung Nexus 7. Also, but not mandatory, what you will need is an NFC tag or sticker. Be sure the NFC tag is pre-formatted because a bug in Android 4.0.2 may prevent you from encoding completely blank tags.

Getting started

Before we can make use of NFC we need to add a few new tags to our manifest XML. I recommend you open up the sample code, as I will be highlighting the key parts on this page. When you have the project imported, open up AndroidManifest.xml in the XML view.

<uses-feature android:name="android.hardware.nfc" android:required="true" />
 
<uses-permission android:name="android.permission.NFC" />

<activity android:name=".ReadTagActivity"
         android:screenOrientation="portrait"
         android:label="@string/title_activity_readtag"
         android:parentActivityName=".MainActivity">
           
      <intent-filter>
            <action android:name="android.nfc.action.NDEF_DISCOVERED" />
            <category android:name="android.intent.category.DEFAULT" />
              <data android:mimeType="application/com.elsinga.sample.nfc" />
            </intent-filter>          
</activity>

The uses-permission tag will allow us to access the NFC chip in the device, and the uses-hardware tag will make it required, which will mean our app only appears to NFC enabled devices in Google Play.
For our ReadTagActivity tag we add a new intent-filter, this will launch the activity when a tag is scanned that contains data in our format. We do this by specifying a custom mime-type, in this case I’ve chosen “application/com.elsinga.sample.nfc”. Android handles NFC tag scans by trying to find the best match for the data on the tag, providing several fallback mechanisms to make sure the tag is handled by the right app and allowing the user to pick from a chooser dialog when there is no clear target.

The first thing we need to do is write some data to a blank NFC tag, so open up WriteTagActivity.java. This activity is launched when the user clicks the “Write button” in the app’s main activity. It displays a button that, when pressed, waits for a tag to write to.

In our onCreate() we grab a reference to the NFC adapter for later use:

_nfcAdapter = NfcAdapter.getDefaultAdapter(this);

The NfcAdapter allows us to begin listening to a tag being scanned, before any other app gets a chance. This is called “foreground dispatch”. When the user presses the button we call enableTagWriteMode() to begin this process. In this method we set up a PendingIntent to run when a tag gets scanned, in this case we simply want the Intent to launch the current Activity when any tag gets scanned, so set up no special filters. When the system dispatches ACTION_TAG_DISCOVERED, this Activity will launch and onNewIntent() will get called with the tag details.

  @Override
  protected void onNewIntent(Intent intent)
  {
    if (_writeMode)
    {
      if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED))
      {
        Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        writeTag(buildNdefMessage(), detectedTag);

        _imageViewImage.setImageDrawable(getResources().getDrawable(R.drawable.android_blue_logo));
        _editTextData.setEnabled(true);
      }
    }
  }

In onNewIntent() we pull out the NFC Tag and begin writing to it in writeTag().

NDEF

The data we store is organised into NDEF Records inside a single NDEF Message. The first thing we do is to determine whether the tag is already NDEF formatted by calling Ndef.get(tag). If it’s already NDEF formatted we check if it’s writeable and that the data is not too large. With all being well we write the data with ndef.writeNdefMessage(). That’s it, we’ve written to an NFC tag!

If you go to the home screen, or exit the app, and re-scan the tag, it should now launch the ReadTagActivity and show the text.
Open up ReadTagActivity.java to see how we read the information from the Intent:

  NdefMessage[] getNdefMessagesFromIntent(Intent intent)
  {
    // Parse the intent
    NdefMessage[] msgs = null;
    String action = intent.getAction();
    if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED) || action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED))
    {
      Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
      if (rawMsgs != null)
      {
        msgs = new NdefMessage[rawMsgs.length];
        for (int i = 0; i < rawMsgs.length; i++)
        {
          msgs[i] = (NdefMessage) rawMsgs[i];
        }

      }
      else
      {
        // Unknown tag type
        byte[] empty = new byte[]{};
        NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN, empty, empty, empty);
        NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
        msgs = new NdefMessage[]{msg};
      }

    }
    else
    {
      Log.e(TAG, "Unknown intent.");
      finish();
    }
    return msgs;
  }

With that determined we can go ahead and grab the NdefMessage from the Intent’s extras. In our case we know the first NdefRecord is the record we want, containing our written text in the payload:

    if (getIntent().getAction() != null)
    {
      if (getIntent().getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED))
      {
        NdefMessage[] msgs = getNdefMessagesFromIntent(getIntent());
        NdefRecord record = msgs[0].getRecords()[0];
        byte[] payload = record.getPayload();

        String payloadString = new String(payload);

        _textViewData.setText(payloadString);
      }
    }

    _nfcAdapter.enableForegroundDispatch(this, _nfcPendingIntent, _readTagFilters, null);

That’s it. We have managed to write custom data to an NFC tag, and read back that custom data.
Have a look at the sample code and also discover how to beam data from one NFC-enabled device to another.

  1. Pingback: FrAndroid DevTips #28 - FrAndroid

  2. Claudio Petrachi
    Hello, your work is very interesting. I have a question about NFC. Is it possible to increase power in write phase? Thank a lot Claudio
  3. AFi
    Hi,I am trying your NFC example given on this link https://github.com/welsinga . . It is not working for me,Message not going on Device B,I am testing on Samsung Devices S3 and S2Plus . . I want to send some text data from one device to device B using NFC . . Both Devices are with Jelly Bean,

Leave a Reply

*

captcha *