September 1, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

NFC Programming in Android

  • March 25, 2013
  • By Chunyen Liu
  • Send Email »
  • More Articles »

Android NFC Resources, Requirements, and Setup

Android's NFC support page is where you can find API documentation and some NFC sample codes.

What do you need to start your project? There are generally some hardware requirements and permissions you want to confirm with your app. They can be specified in your Android manifest file,AndroidManifest.xml. The minimum Android SDK version should be set to level 10:

<uses-sdk android:minSdkVersion="10"/>

Also, your app user's devices need to have NFC hardware and your app should have permission to interact with the hardware:

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

There are also optional NFC intents you can filter to handle the type of data scanned from NFC tags as follows. This is just a generic example to handle plain text data from the intent actionNDEF_DISCOVERED. There are other types of data defined in NFC specifications as well. Nevertheless, you can also achieve the same goal with the foreground tag dispatch system.

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

NFC Data Exchange Format

NdefMessage contains the data transferred in NFC Data Exchange Format (NDEF). Each NdefMessage can be comprised of multiple records defined in NdefRecord. Each NdefRecord is interpreted according to its type definition specified in the 3-bit Type Name Format (TNF). Check out the complete listing for supported TNFs and their mappings. The most commonly used TNFs areTNF_WELL_KNOWN and TNF_MIME_MEDIA.

The tag dispatch system handles the unpacking of the NFC data through three intents, with data inside the intent bundle. From highest to lowest priority, they are ACTION_NDEF_DISCOVERED, ACTION_TECH_DISCOVERED, and ACTION_TAG_DISCOVERED. With official site's recommendation, "Whenever possible, work with NDEF messages and the ACTION_NDEF_DISCOVERED intent, because it is the most specific out of the three. This intent allows you to start your application at a more appropriate time than the other two intents, giving the user a better experience."

Reading NFC Tags and Stickers in Android

Figure 1 shows some miscellaneous NFC tags and stickers. They are available in many stores and vary in memory sizes and supported technologies.

NFC Tags / Stickers
Figure 1: NFC Tags / Stickers

As we mention in the previous section, NdefMessage is the most generic way of exchanging NFC data. You can still define your own non-NDEF data format but that is beyond the scope of this tutorial. To illustrate how data is parsed and handled by the tag dispatch system, we only focus on the simple plain text type in our example. For other data types, you should check into the official site for the complete listing.

NfcAdapter is used to check the device NFC support. We use the option enableForegroundDispatch to indicate the tag dispatch is handled when the app is running on the foreground. The foreground dispatch system allows an activity to intercept an intent and claim priority over other activities that handle the same intent.

In onNewIntent(), we try to parse all NDEF messages and their records. Since there are several different data types, the example only tries to parse the pain text type as defined inNdefRecord.RTD_TEXT. Figure 2 shows the parsed result by receiving the data send by the beaming example in the next section.

public class TagDispatch extends Activity {
    private TextView mTextView;
    private NfcAdapter mNfcAdapter;
    private PendingIntent mPendingIntent;
    private IntentFilter[] mIntentFilters;
    private String[][] mNFCTechLists;
 
    @Override
    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);
 
        setContentView(R.layout.main);
        mTextView = (TextView)findViewById(R.id.tv);
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
 
        if (mNfcAdapter != null) {
            mTextView.setText("Read an NFC tag");
        } else {
            mTextView.setText("This phone is not NFC enabled.");
        }
 
        // create an intent with tag data and deliver to this activity
        mPendingIntent = PendingIntent.getActivity(this, 0,
            new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
 
        // set an intent filter for all MIME data
        IntentFilter ndefIntent = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        try {
            ndefIntent.addDataType("*/*");
            mIntentFilters = new IntentFilter[] { ndefIntent };
        } catch (Exception e) {
            Log.e("TagDispatch", e.toString());
        }
 
        mNFCTechLists = new String[][] { new String[] { NfcF.class.getName() } };
    }
 
    @Override
    public void onNewIntent(Intent intent) {
        String action = intent.getAction();
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
 
        String s = action + "\n\n" + tag.toString();
 
        // parse through all NDEF messages and their records and pick text type only
        Parcelable[] data = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (data != null) {
            try {
                for (int i = 0; i < data.length; i++) {
                    NdefRecord [] recs = ((NdefMessage)data[i]).getRecords();
                    for (int j = 0; j < recs.length; j++) {
                        if (recs[j].getTnf() == NdefRecord.TNF_WELL_KNOWN &&
                            Arrays.equals(recs[j].getType(), NdefRecord.RTD_TEXT)) {
                            byte[] payload = recs[j].getPayload();
                            String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16";
                            int langCodeLen = payload[0] & 0077;
 
                            s += ("\n\nNdefMessage[" + i + "], NdefRecord[" + j + "]:\n\"" +
                                 new String(payload, langCodeLen + 1, payload.length - langCodeLen - 1,
                                 textEncoding) + "\"");
                        }
                    }
                }
            } catch (Exception e) {
                Log.e("TagDispatch", e.toString());
            }
        }
 
        mTextView.setText(s);
    }
 
    @Override
    public void onResume() {
        super.onResume();
 
        if (mNfcAdapter != null)
            mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, mIntentFilters, mNFCTechLists);
    }
 
    @Override
    public void onPause() {
        super.onPause();
 
        if (mNfcAdapter != null)
            mNfcAdapter.disableForegroundDispatch(this);
    }
}

NFC Tag Dispatch Example
Figure 2: NFC Tag Dispatch Example

Sending NFC Data to Other Devices Through Android Beam

Sending NFC data is through the support of Android Beam, so this activity is commonly referred to as "beaming". Many NDEF data types can be beamed and of course, you can also customize your own format. The example illustrates how you can create the records for plain text type. Most of the codes should look familiar, so createNewTextRecord is the key portion you need to pay attention to. We put two NdefRecord records inside the NdefMessage data.

public class BeamData extends Activity {
    private NfcAdapter mNfcAdapter;
    private TextView mTextView;
    private NdefMessage mNdefMessage;
 
    @Override
    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);
 
        setContentView(R.layout.main);
        mTextView = (TextView)findViewById(R.id.tv);
 
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
 
        if (mNfcAdapter != null) {
            mTextView.setText("Tap to beam to another NFC device");
        } else {
            mTextView.setText("This phone is not NFC enabled.");
        }
 
        // create an NDEF message with two records of plain text type
        mNdefMessage = new NdefMessage(
                       new NdefRecord[] {
                       createNewTextRecord("First sample NDEF text record", Locale.ENGLISH, true),
                       createNewTextRecord("Second sample NDEF text record", Locale.ENGLISH, true) });
    }
 
    public static NdefRecord createNewTextRecord(String text, Locale locale, boolean encodeInUtf8) {
        byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
 
        Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
        byte[] textBytes = text.getBytes(utfEncoding);
 
        int utfBit = encodeInUtf8 ? 0 : (1 << 7);
        char status = (char)(utfBit + langBytes.length);
 
        byte[] data = new byte[1 + langBytes.length + textBytes.length];
        data[0] = (byte)status;
        System.arraycopy(langBytes, 0, data, 1, langBytes.length);
        System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
 
        return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data);
    }
 
    @Override
    public void onResume() {
        super.onResume();
 
        if (mNfcAdapter != null)
            mNfcAdapter.enableForegroundNdefPush(this, mNdefMessage);
    }
 
    @Override
    public void onPause() {
        super.onPause();
 
        if (mNfcAdapter != null)
            mNfcAdapter.disableForegroundNdefPush(this);
    }
}

Conclusion

This beginning NFC tutorial is mainly to highlight some key aspects as starting points. We cover basic NFC data format, how to read from NFC tags, and how to beam data to other devices. NFC-capable devices or tags can involve various technologies. You can use the getTechList() method to determine the supported technologies and create the corresponding classes provided byandroid.nfc.tech .

The entire software package is downloadable from the references for you to experiment with. Personally, I also pick up lots of NFC related info from Wikipedia's entry. There are some NFC apps at Google Play you might find interesting as well: NFC Task Launcher, NFC TagInfo, NFC TagWriter, NFC Contacts.

Android NFC References

1.     Download and save the entire software project

2.     Android NFC

3.     Android Developers at: http://www.android.com/developers/

4.     Androidlet at http://www.androidlet.com

Download TutorialOnNFC.zip

About the Author:

Chunyen Liu has been a software professional for years. He was among winners at programming contests administered by SUN, ACM, and IBM. He has co-authored software patents, written 25+ articles, reviewed books, and published apps at Androidlet and The J Maker. He holds advanced degrees in Computer Science with 20+ graduate-level courses taken. On the non-technical side, he is a tournament-ranked table tennis player, certified umpire, and certified coach of USA Table Tennis.


Tags: Android, RFID, NFC, radio frequency identification, near field communication




Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel