Writing tags with Nexus S

Posted on Jan 14, 2011 - By

As said by Google CEO Eric Schmidt two month ago, the operating system Android 2.3  includes support for near field communication. But, at least in terms of the API and the sample code they supply, this version only includes tag reading capability. However, the  PN544 NFC chip inside the Nexus S supports read and write operations so, at the hardware level, all the functionality you need to support a full range of NFC services is in the handset. At the software level, there will be updates to the SDK rolled out on a phased basis that will enable developers to write NFC applications for mobile payments, p2p and other applications on Android Gingerbread devices.

We’ve been analyzing the  Android kernel source code and we found a lot of “@hide” tags in the NFC java classes. These are in:

frameworks/base/core/java/android/nfc
frameworks/base/core/java/com/android/internal/nfc
packages/apps/Nfc (the android service running in the background)
packages/apps/Tag (the application used to read and store tags)

And the hardware abstraction layer from NXP is in:

external/libnfc-nxp

Let’s see an example, the publised API for the class NCFAdapter has only two public methods:

getDefaultAdapter(): Get a handle to the default NFC Adapter on this Android device.
isEnabled(): Return true if this NFC Adapter has any features enabled.

But also has this public methods with the @hide tag:

enable(): Enable NFC hardware.
disable(): Disable NFC hardware.
createRawTagConnection(): Create a raw tag connection to the default Target.
createNdefTagConnection(): Create an NDEF tag connection to the default Target .

Interesting, isn’t it?

The “@hide” tag is used to mark public APIs that are not to be exported in the SDK. This is used by the Android team to have APIs accessible across packages without having them available to applications. APIs marked with @hide are considered private to the Android platform and can change at any time, so you cannot rely on them. So, with this in mind, we can confirm that there is some extended NFC functionality hidden in Android 2.3 that can be accessed, i.e. with reflection techniques. Let’s see how we can do this.

To write tags we’ll use the write() method from the INfcTag interface, so lets dive from NfcAdapter to the INfcTag. First we need a handle to the NFC adapter within the Nexus S:

NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter();

Then we need a handle to the actually detected tag, this is done by getting the the data within the intent received when tag was discovered:

Parcelable nfcTag = intent.getParcelableExtra("android.nfc.extra.TAG");
Field f = nfcTag.getClass().getDeclaredField("mServiceHandle");
f.setAccessible(true);
Object mServiceHandle = f.get(nfcTag);

Now, we can create a raw connection to the tag, this is a low-level connection to a tag target. We’ll use this object to get later a handle to the INfcTag

Class tag = Class.forName("android.nfc.Tag");
Method createRawTagConnection = nfcAdapter.getClass().getMethod("createRawTagConnection", tag);
Object rawTagConnection = createRawTagConnection.invoke(nfcAdapter, nfcTag);

Now we can get the handle to the INfcTag interface (mTagService).

Field f = rawTagConnection.getClass().getDeclaredField("mTagService");
f.setAccessible(true);
Object mTagService = f.get(rawTagConnection);

Before we can write to the tag we connect our interface to it.

Method connect = mTagService.getClass().getMethod("connect", Integer.TYPE);
connect.invoke(mTagService, mServiceHandle.intValue());

Finally, we create the NdefTagRecord, this could be a smart poster, an uri, simple text or whatever record we want to write into the tag. This record will be encapsulated into an NdefMessage, so when we invoke the write() method we use this ndefMessage as parameter:

Method write = mTagService.getClass().getMethod("write", Integer.TYPE, NdefMessage.class);
write.invoke(mTagService, mServiceHandle, ndefMessage);

… and that’s it!
The write() method will work as long as you use a tag pre-formatted with any NFC Forum type tag with default public keys.
We developed an application using this code to write tags. Below you can see a demo of this app writing an URI type tag:

Tagged , , , .

53 Comments

  • Mike Clark says:

    That’s a nice piece of work! We’ve written about it in NFC World:

    http://www.nearfieldcommunicationsworld.com/2011/01/25/35758/

    Mike :)

  • Elad Katz says:

    Can you post a link to the app for testing purposes or at least to the complete source code?
    Thanks!
    Great Work!

  • I would love to be able to download the app you have in your demo to test it on my phone too.

    (With or without the source code.)

    Gab

  • dean collins says:

    just to clear up my understanding in this space – the android doesnt use a “published” NFC standard right? so the iPhone tags wont be read by nexus phones or vice versa right?

  • Hi, Dean. Android actually USE the published NFC standards about NDEF messages and records (uri/text/smart poster) to read tags. The one that we used in the demo was a mifare classic with NFC Forum standard info stored inside it. So, as long as the iPhone tags complain these standards Nexus will read them.

  • Mark Rose says:

    Hi
    Thats a great development for the Nexus s and we would be very interested to know you be releasing your app to purchase through google Market?

  • Dear Gustavo,
    that’s great news indeed! I’m working on the new visitor information system for the Capitoline Museums based on NFC tags (5230 phones and MIFAR tags). A Nexus S will soon be available to me, too, and I would surely be interested in the app.

  • will says:

    Been trying this with a MiFare 4k card, and the write command is always returning an unknown error. Can you post some simple code to show how you’ve created the NdefMessage so I can compare it against my code? Thx.

  • Objecs says:

    Nice work guys. You may already have discovered this with your work, but we learned from some of our U.S. customers about some strange problems reading our NFC enabled products (including the card type you are using in your demo) with the Nexus phone.

    http://www.personalrosettastone.com/

    It didn’t take long to discover that the OS aborts the read if the URL is too long. In fact if your product or tag, such as ours, has a detail section, name or title to go along with the URL then the ability of the Nexus S to read the NFC is very unlikely. This is a pretty significant problem for this phone. Even if you don’t use any title field at all, which is NDEF, then the URI still has some limiting length requirements which users will stumble on as ‘not readable’.

    This is equivalent to your web browser only being able to open web pages that have really short names if the page has a header title, name or supporting detail. If the header is too long you get a 404 error but works fine if you use another browser (i.e. Nokia 6212, etc)

    The Nexus S does have the ability to read the detail section / title as well as the URI field out of the box but we found this limitation in size (total bytes) as quite a surprise, but we suspect they thought NFC was only going to be for payments back when the hardware was designed.

    Let’s keep our fingers crossed that Google discovers this easy fix before consumers start coding tags with tools such as yours. If not it might users shaking their heads about this technology I’m afraid.

    AZCoder,
    Objecs Technical support.

    PersonalRosettaStone.com

  • Hari says:

    “The write() method will work as long as you use a tag pre-formatted with any NFC Forum type tag with default public keys.”

    Where can I get cards? Do MiFare cards come pre-formatted.

  • Alexandre Gherschon says:

    Hi, I tried the code an got the next error:

    01-31 10:45:49.238: WARN/System.err(2003): java.lang.NoSuchFieldException: mServiceHandle

    On the obvious line:

    Field f = nfcTag.getClass().getDeclaredField(“mServiceHandle”);

    However, I can see this attribute when debugging the variable nfcTag.

    Any idea why this doesn’t work?
    Thanks by advance!

  • Yoav says:

    Can you please publish / send by email a sample application or an executable that works for 2.3.3?
    I just want to buy several empty tags to play with.
    Thanks!

  • To Alexandre Gherschon,

    Remember to get the intent when the tag was discovered:

    Intent intent = getIntent();

  • Paul Macfarlane says:

    Managed to get this working with Mifare Classic 1k label tag…very basic but does the job of writing any url placed in the text box to the tag. Doing NFC for my honours project at uni and it comes in very handy to be able to write to the tags using my Nexus S so thanks.

  • Paul Macfarlane says:

    I refer you to a page created by Adam Rocker, this is not mine and I take no credit.

    http://translate.google.co.uk/translate?hl=en&sl=ja&u=http://www.adamrocker.com/&ei=OEVITfYCxcuEB4T_kIEF&sa=X&oi=translate&ct=result&resnum=2&ved=0CCQQ7gEwAQ&prev=/search%3Fq%3Dadamrocker%2B/blog/%26hl%3Den%26prmd%3Divns

    There is a very useful Zip file on there (SOURCE CODE!) which implements tag writing on the Nexus S.

  • Asif says:

    Gustavo

    Intent intent = getIntent();

    This line means that we will have to have an intent originated by discovery of an NFC tag. But what if we don’t want discovery of an NFC tag rather we just want to start an activity from the Launcher and then we want to write the tag by clicking on a button from within that activity.

    Also for NdefMessage I will put a fake tag as they are available inside MockNdefMessages class of the NFCDemo available in the Android SDK.

    Regards,
    Asif

  • Asif,

    Even if you start an activiy from the launcher to click a button and write a tag, you’ll need the tag in the antenna’s field, so your app will be able to write the ndefmessage. At that moment the NFCService running in the background will discover the tag and broadcast the TAG_DISCOVERED intent anyway.

    Regards

  • Steve McRae says:

    We have tested the nexus s to read 16 blocks of data (256 bytes), not quite a full Mifare1k tag (45 addressable blocks) but plenty of data for URL or messages. We have found that the smart poster record however is very particular and it took allot of testing to figure out how it was implemented in Android 2.3. Because there are many variations of the smart poster configurations (which is just a number of other NDEF records packed into a single message) we find that implementations are not always as flexible as NFC Forum would have liked them to be so you have to follow some more common practices with your smart poster rather than using the NFC Forum specification as written.

    Anyone looking for tags, NFC reader/writer, and application to write NDEF messages you can get it here: http://mobifyer.com

    We put together an Android developers kit to help people test their applications and get setup for real world deployments.

  • Philipp Hug says:

    I used the method to access an ISO 14443 smart card.
    It works as long as the APDUs are not too long.
    It really looks like there’s either a length or time limit for requests or responses.
    Has anyone looked into this?

  • Praveen says:

    Hi,

    Anybody managed establish a P2P connection between Nexus S and ACR122U Tag Reader ?

    Help is much appreciated.

    Thanks,
    Praveen

  • Vineet says:

    No..

    NFCAdapter.getDeafultAdapter(this) returns null on my Nexux S

  • This is valid for android 2.3.1.

  • Vineet says:

    <This is valid for android 2.3.1.

    but I have Android 2.3.4 onNexus S

    and still

    NFCAdapter.getDeafultAdapter(this) returns null

  • Vineet says:

    OK. My problem is solved. I had to correct my manifest.xml

Trackbacks and Pingbacks