Showing posts with label Getting started with NFC on Android. Show all posts
Showing posts with label Getting started with NFC on Android. Show all posts

Getting started with NFC on Android

  • nowledge needed: Intermediate Android
  • Requires: NFC-enabled Android phone
  • Project time: 30 minutes

Near Field Communication (NFC) enables wireless communication between things like phones, stickers and cards. In this tutorial Richard Leggett shows us how to write a game demo that both reads and writes custom data to an NFC tag

NFC or “Near Field Communication” is a technology that allows wireless close-proximity data communication between things like phones, stickers and cards. If you’re familiar with Barclays PayWave or the Oyster Card, you’ll know that the technology this is built on, “RFID”, allows data to be read by simply touching things together. You might touch a phone against stickers, posters and with NFC, other phones. This action can be used to launch a website or an app, make a payment or even transfer data in both directions (on Android the latter is called Beam). When compared to QR codes, NFC provides a far simpler (and built-in) mechanism for opening URLs, downloading apps, or even reading and writing custom content.



Getting started with NFC on Android

Getting started with NFC on Android

Near Field Communication (NFC) enables wireless communication between things like phones, stickers and cards. In this tutorial Richard Leggett shows us how to write a game demo that both reads and writes custom data to an NFC tag

NFC or “Near Field Communication” is a technology that allows wireless close-proximity data communication between things like phones, stickers and cards. If you’re familiar with Barclays PayWave or the Oyster Card, you’ll know that the technology this is built on, “RFID”, allows data to be read by simply touching things together. You might touch a phone against stickers, posters and with NFC, other phones. This action can be used to launch a website or an app, make a payment or even transfer data in both directions (on Android the latter is called Beam). When compared to QR codes, NFC provides a far simpler (and built-in) mechanism for opening URLs, downloading apps, or even reading and writing custom content.
In this tutorial we’re going to build an app that writes to NFC tags, and also reads Top Trumps-like data from them for a retro console game. If a user without our app touches the tag, it’ll use a built in mechanism to take them to the download page for the app in the Android Play Store. Once installed any subsequent taps will launch the app and show the game card on screen. All in less than 200 lines of code!
In order to follow along you will need an NFC enabled Android phone such as the Samsung Galaxy Nexus or Samsung Nexus S. The other thing you will need is a few NFC tags or stickers. You can find these many places online but RapidNFC offer a great starter pack, which includes a variety of re-writable tags and the website also includes a good amount of info around the different tag types. Be sure to order them pre-formatted (this appears as an option after payment), a bug in Android 4.0.2 may prevent you encoding completely blank tags.
Before we start writing our own code I’d also recommend downloading NXP TagWriter to get you familiar with reading and writing your tags.
Along with reading and writing text and URLs you can enable “professional mode” for free in the app’s preferences screen (accessible via the menu button). Once enabled this gives you the ability to format/erase and write-protect tags.


Getting started

Now onto our app… The first job is to write some data to a blank tag. We’re going to be including a special record which links to the app download page, and the game data itself in NDEF (NFC Data Exchange Format).
I recommend you open up the source code at this point, 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.
Before we can make use of NFC we need to add a few new tags to our manifest XML:
  • View source
  • Copy code
  1. <uses-permission android:name="android.permission.NFC" />
  2. <uses-feature android:name="android.hardware.nfc" android:required="true" />
  3. <activity android:name=".CardActivity"
  4. >
  5.             <intent-filter>
  6.                 <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
  7.                 <data android:mimeType="application/vnd.netmagazine.nfcdemo"/>
  8.                 <category android:name="android.intent.category.DEFAULT"/>
  9.         </intent-filter>        
  10. </activity>
The uses-permission tag will allow us to access the NFC chip in the phone, and the uses-hardware tag will make it a requirement, which will mean our app only appears to NFC enabled phones in the Play Store. For our CardActivity tag we add a new intent-filter, this will launch the activity when a tag is scanned that contains data in our game format. We do this by specifying a custom mime-type, in this case I’ve chosen “application/vnd.netmagazine.nfcdemo”. 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 MainActivity.java. This activity is launched when the user clicks the app’s icon. 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:
  • View source
  • Copy code
  1. mAdapter = NfcAdapter.getDefaultAdapter(this);
The NfcAdapter allows us to begin listening to tag being scanned, before any other app gets a chance. This is called “foreground dispatch”. When the user presses the button we call enableWriteMode() to begin this process:
  • View source
  • Copy code
  1. private void enableWriteMode() {
  2. mInWriteMode = true;
  3. PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
  4.             new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
  5. IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
  6.         IntentFilter[] filters = new IntentFilter[] { tagDetected };
  7.        
  8. mAdapter.enableForegroundDispatch(this, pendingIntent, filters, null);
  9. }
In this method we set up a PendingIntent to run when a tag gets scanned, in this case we simply want to 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.
  • View source
  • Copy code
  1. public void onNewIntent(Intent intent) {
  2. if(mInWriteMode) {
  3.                 mInWriteMode = false;
  4.                                
  5.                 Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  6.                 writeTag(tag);
  7. }
  8. }
In onNewIntent() we pull out the NFC Tag and begin writing to it in writeTag(). This is by far the largest method in our demo:
  • View source
  • Copy code
  1. private boolean writeTag(Tag tag) {
  2. // record to launch Play Store if app is not installed
  3.         NdefRecord appRecord = NdefRecord.createApplicationRecord("com.netmagazine.nfcdemo");
  4.                
  5.         // record that contains our custom "retro console" game data, using custom MIME_TYPE
  6.         byte[] payload = getRandomConsole().getBytes();
  7.         byte[] mimeBytes = MimeType.NFC_DEMO.getBytes(Charset.forName("US-ASCII"));
  8.         NdefRecord cardRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload);
  9.         NdefMessage message = new NdefMessage(new NdefRecord[] { cardRecord, appRecord});
  10.        
  11. try {
  12.                 // see if tag is already NDEF formatted
  13.                 Ndef ndef = Ndef.get(tag);
  14.                 if (ndef != null) {
  15.                         ndef.connect();
  16.                         if (!ndef.isWritable()) {
  17.                                 displayMessage("Read-only tag.");
  18.                                 return false;
  19.                         }
  20. // work out how much space we need for the data
  21. int size = message.toByteArray().length;
  22.                         if (ndef.getMaxSize() < size) {
  23.                                 displayMessage("Tag doesn't have enough free space.");
  24.                                 return false;
  25.                         }
  26.                         ndef.writeNdefMessage(message);
  27.                         displayMessage("Tag written successfully.");
  28.                         return true;
  29.                 } else {
  30.                         // attempt to format tag
  31.                         NdefFormatable format = NdefFormatable.get(tag);
  32.                         if (format != null) {
  33.                                 try {
  34.                                         format.connect();
  35.                                         format.format(message);
  36.                                         displayMessage("Tag written successfully!");
  37.                                         return true;
  38.                                 } catch (IOException e) {
  39.                                         displayMessage("Unable to format tag to NDEF.");
  40.                                         return false;
  41.                                 }
  42.                         } else {
  43.                                 displayMessage("Tag doesn't appear to support NDEF format.");
  44.                                 return false;
  45.                         }
  46.                 }
  47.         } catch (Exception e) {
  48.                 displayMessage("Failed to write tag");
  49.         }
  50. return false;
  51. }

NDEF

The data we store is organised into NDEF Records inside a single NDEF Message. The first thing we do is create an “application record”, appRecord. This is something new to Android 4, it forces the system to launch your app before others if a matching package name is found in the NFC tag. After that we create our cardRecord which contains a randomly generated game console. The payload is where we store our custom data, in this case simply a game console’s name in lower case.
Next we determine whether the tag is already NDEF formatted by calling Ndef.get(tag). If it’s already NDEF formatted we check it’s writeable and that the data is not too large. With all being well we write the data with ndef.writeNdefMessage(). If the tag was not already NDEF formatted we use NdefFormattable.format() to write the data at the same time as formatting the tag. That’s it, we’ve written an NFC tag!
With the tag written hit the home button to exit the app and re-scan the tag. It should now launch the CardActivity and show the console’s game card. Open up CardActivity.java to see how we read the information from the Intent:
  • View source
  • Copy code
  1. Intent intent = getIntent();
  2. if(intent.getType() != null && intent.getType().equals(MimeType.NFC_DEMO)) {
  3.    Parcelable[] rawMsgs =
  4. getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
  5.     NdefMessage msg = (NdefMessage) rawMsgs[0];
  6.     NdefRecord cardRecord = msg.getRecords()[0];
  7.     String consoleName = new String(cardRecord.getPayload());
  8.     displayCard(consoleName);
  9. }
Here we are simply checking the Intent to make sure the type matches our custom mime-type. 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 our cardRecord, containing our console name in the payload. With the console name known we simply show the correct image in an ImageView.
In very little time we’ve managed to write custom data to an NFC tag, automatically download an app to read it and read back that custom game data. From here you could expand the demo to become a fully playable game and even use Android Beam’s phone to phone NFC to make it multiplayer.