Near Field Communication (NFC) in Android - Advanced tutorial: Use Android smartphone to read complex NFC payload
NFC
NDEF Record structure
Read NFC payload
NFC Smart poster, text, link
This post describes how to read complex NFC tag in Android. As we said in the previous post, explaining how to implement Android NFC app , there are several type of NFC (NDEF) tag:
- NFC Forum well-known type [NFC RTD]
- Media-type as defined in RFC 2046
- Absolute URI as defined in RFC 3986
- NFC Forum external type [NFC RTD]
short tnf = record.getTnf();
Comparing the tnf (Type Name Format) with all possible combination, we can know the record type. In the code above record is an instance of NdefRecord.
NFC - NDEF Record Structure
Before analysing how to read NDEF content, it is important to know the NDEF record structure. The picture below shows the structure:The most important byte (7th) is the Message Begin byte, this byte is 1 if the it is the starting message otherwise is zero. The 6th byte is the Message End, this byte is 1 if the this record is the end record otherwise is 0. SR is the Short Record and it is 1 if it is a short record. This information are important if we want to handle the NDEF tag data correctly.
We know that Android SDK provides the method
getPayload()
that returns an array of bytes that represent the tag content. We have to read and parse this array to extract information.Let's start from the simplest record structure: text record.
NFC Well-known type: Text Record
The NFC Well-Known type is the simplest record type and we will start from here. To get the NFC payload, the first thing to do is reading the header (payload[0]) and parse it. The most significative byte (the 7th) represent the text encoding:byte status = payload[0];
int enc = status & 0x80; // Bit mask 7th bit 1
String encString = null;
if (enc == 0)
encString = "UTF-8";
else
encString = "UTF-16";
The bit from 5th to 0 represents the language length:
int ianaLength = status & 0x3F; // Bit mask bit 5..0
Now we are ready to read the "real" content:
try {
String content = new String(payload, ianaLength + 1, payload.length - 1 - ianaLength, encString);
record.payload = content;
}
catch(Throwable t) {
t.printStackTrace();
}
Let us suppose we create simple text/plain content with Surviving with Android. Now if we read the content we have:
02 65 6e 53 75 72 76 69 76 69 6e 67 20 77 69 74 68 20 61 6e 64 72 6f 69 64
This is the NFC payload, and if we parse it we get:
NFC Forum external type
This is another simple NDEF content. This type of content is built for organization that want to create a custom name space. This type of content can be useful when we want to create a special name space to run an app for example. Reading it is very simple:StringBuffer pCont = new StringBuffer();
for (int rn=0; rn < payload.length;rn++) {
pCont.append(( char) payload[rn]);
}
All the NFC payload is the content.
NFC NDEF Smart poster
This is the most complex NDEF tag, because it can be made by several inner contents made by several types. In this case is very important to read the message header to know if the record is a Message Begin or Message end or if the record is a Short Record.The first thing we have to do is read the header:
int[] result = getHeader(payload); // 0 = MB, 1 = ME, 2 = SR
int numLenByte = 1;
if (result[2] == 0)
numLenByte = 4; // This is not a Short Record. Length = 4 byte
Now we know how many bytes is the payload length and then we have to get the length:
String byteLen = "";
for (int p = 2; p <= 2 + numLenByte - 1; p++)
byteLen = byteLen + payload[p]; // We simply append the bytes
Then we read the record type to know how to handle it:
int pos = 2 + numLenByte;
int type = payload[pos];
We can parse the payload according to the record type:
if (type == 'U') {
RDTUrl url = new RDTUrl();
result = getHeader(payload);
url.MB = result[0];
url.ME = result[1];
url.SR = result[2];
url.prefix = payload[pos];
Log.d("NFC", "Action:" + "0x" + Integer.toHexString(url.prefix));
url.url = new String(payload, pos + 1, Integer.parseInt(byteLen) - 1);
Log.d("NFC", "Content:" + url.url);
record.records.add(url);
}
else if (type == 'T') {
RDTTextRecord text = new RDTTextRecord();
result = getHeader(payload);
text.MB = result[0];
text.ME = result[1];
text.SR = result[2];
int len = payload[pos];
Log.d("Nfc", "Lan len ["+len+"]");
text.language = "";
for (int i = pos + 1; i <= pos + len; i++)
text.language = text.language + (char) payload[i];
Log.d("Nfc", "Lang ["+text.language+"]");
text.payload = new String(payload, pos + len + 1, Integer.parseInt(byteLen) - len - 1);
Log.d("NFC", "Content:" + text.payload);
record.records.add(text);
}
}
And finally we move to the next message part:
payload = Arrays.copyOfRange(payload, pos + Integer.parseInt(byteLen), payload.length);
...and of course we repeat all these things until the payload length is greater than 0. That's all.
Let us suppose we a NDEF Tag that has a link that points to this website and a text part like surviving.
The payload is:
ffffff91 1 19 55 1 73 75 72 76 69 76 69 6e 67 77 69 74 68 61 6e 64 72 6f 69 64 2e 63 6f 6d 51 1 c 54 2 65 6e 73 75 72 76 69 76 69 6e 67
Now, if we run our app we get:
We can suppose now we have a tag containing a telephone number with a label:
Source code available @github
Now, you know how to read NFC tags in Android, extract the content from the payload and develop a NFC application in Android.
0 comments:
Post a Comment