Introduction
This article is part of a series intended to act as an introduction to the world of NFC as it applies to BlackBerry® smartphones such as the BlackBerry® Bold™ 9900 and is aimed at developers who wish to take advantage of this exciting new technology. Readers of this article should have some pre-existing knowledge of the fundamental architecture of NFC systems and be familiar with the BlackBerry® WebWorks™ SDK. Familiarity with Java® is required for those parts of the article which deal with the sample WebWorks extension that illustrates how to add NFC NDEF capabilities to a WebWorks application.
Importantly, unless you already have good knowledge of the subjects covered, it’s recommended that you read the articles in this series entitled: "NFC Primer for Developers" and “Reading and Writing NFC Smart Tags”. Links to these articles can be found at the end of this one.
This article will look specifically at an example WebWorks extension which allows WebWorks applications to read NFC Smart Posters.
The Authors
This article was co-authored by Martin Woolley , John Murray and Rob Williams all of whom work in the RIM Developer Relations team and specialise in NFC applications development (amongst other things).
About this article
The BlackBerry® 7.0 Java APIs provide BlackBerry Java developers with the ability to read and write NFC tags. However, what about BlackBerry WebWorks developers? Well, as this article and attached sample code will illustrate, WebWorks developers too can quite easily exploit NFC in their applications.
BlackBerry Web Works Extensions
The BlackBerry WebWorks SDK allows developers to create great looking and functionally rich BlackBerry applications for either: the BlackBerry smartphone range, the BlackBerry® PlayBook™ tablet or both!
Developers use HTML5, JavaScript® and CSS and can leverage a growing WebWorks API to incorporate native device functionality in their applications. The WebWorks API takes the form of a collection of JavaScript functions that provide functionality relating to a large range of areas. Occasionally however, a developer will find that there is no standard WebWorks API function which does what they want. The WebWorks SDK is extensible and developers can write their own extensions which add new APIs that their WebWorks application can exploit.
At the time of writing, the WebWorks SDK has no standard NFC capabilities. So the authors of this article have put together a WebWorks extension for the BlackBerry smartphone range and the source code is available in the WebWorks GitHub repository (details below). The extension allows WebWorks applications to register to receive NDEF messages. A simple WebWorks application which uses the extension is also in the repository.
Let’s explore what was involved in creating the extension and how it can be used from a simple WebWorks application.
The Sample WebWorks Application
When started, the sample WebWorks application automatically registers as an NDEF listener for NDEF messages relating to “smart posters” and several common image types. It has a simple, one page user interface (as shown in Figure 1) that allows the user to register for “smart posters”, well known image types and a custom type (the interface for the custom type is shown in Figure 2). After registering, an NFC tag (virtual or real) entering the NFC radio field of the BlackBerry smartphone will cause a popup showing certain details of the NDEF message to be displayed (as shown in Figure 3). The JSON representation of the message will be shown in the text area (as shown in Figure 4).
A “real” application would of course do something more interesting with the NDEF message. But we’ll leave such creativity to you, the BlackBerry WebWorks developer.
Figure 1 - WebWorks application user interface
Figure 2 - Custom type registration is selected - so more fields are visible
Figure 3 - Part of a Smart Poster NDEF message is displayed by the WebWorks application
Figure 4 - Part of the JSON message representing an NDEF Smart Poster
The sample application code resides in several files with the essential code in “index.html”. It includes the in-line JavaScript functions shown here:
function initLogging() {
var ok = blackberry.nfc.ndef.init_logging();
if (ok) {
} else {
alert("The was a problem initialising logging");
}
}
function registerListener(record_type) {
var ok = blackberry.nfc.ndef.register_ndef(ndefMessageRecei ved, onNdefError, record_type);
if (ok) {
alert("NDEFMessageListener registered OK for record type "+record_type);
} else {
alert("There was a problem registering a NDEFMessageListener for record type "+record_type)
}
}
function removeListener(record_type) {
var ok = blackberry.nfc.ndef.unregister_ndef(record_type);
if (ok) {
alert("NDEFMessageListener unregistered OK for record type "+record_type);
} else {
alert("The was a problem unregistering the NDEFMessageListener for record type "+record_type)
}
}
// call back functions
function ndefMessageReceived(ndef_message) {
alert("NDEF message:"+ndef_message);
}
function onNdefError(error_message) {
alert("NDEF error:"+error_message);
}
The JavaScript in the index.html page reveals the various API functions exposed or used by the WebWorks extension. These are as follows:
blackberry.nfc.ndef.init_logging()
The extension classes write log messages to the BlackBerry event log if logging has been switched on.
Calling this API function achieves this. You can then extract the log file from your device using the javaloader tool:
javaloader -u eventlog > eventlog.txt
or you may view it on device by keying “ALT+LGLG”.
Notice that messages are logged at the Information level.
blackberry.nfc.ndef.register_ndef(
<callback function>,
<callback error function>,
<NDEF record type>
)
By calling the “register_ndef” function, you register your application’s interest in a specific NDEF record type.
callback function - is the function which will be called when a message of the given record type is received.
callback error function - is the function which will be called when an error occurs in the library / processing a message.
NDEF record type – is the type of record your application is interested in receiving. This parameter must be a string. It is interpreted by the extension in two ways.
For “Sp” – the typeNameFormat should is “well known” (1)
For a MIME like tag – the typeNameFormat should be “media”. (2)
Some useful constants are included in the file blackberry_nfc_ndef.js. (eg: ndef.tnf.WELL_KNOWN). Keep in mind that these constants should be used and evaluated in JavaScript, not passed to the extension.
To register for a “Smart Poster”, your code can do the following:
blackberry.nfc.ndef.register_ndef(funca,funcb,”Sp”
or
blackberry.nfc.ndef.register_ndef(funca,funcb,”{‘t
To register for your own MIME payload, your code can do this:
blackberry.nfc.ndef.register_ndef(funca,funcb,”{‘t
Note that there is a helper function in index.html to create the JSON from two arguments.
blackberry.nfc.ndef.unregister_ndef(
<NDEF record type>
)
By calling unregister_ndef you unregister your application as a listener for the given type.
NDEF record type - is logically the same as in register_ndef. It can be just a type, or a JSON message containing a type and a typeNameFormat.
blackberry.nfc.isNFCAvailable()
At certain times, NFC may not be available on a BlackBerry device which supports it. The most obvious time it is not available is when a user has disabled (or has not enabled) NFC communication in the “Manage Connections” configuration screen.
blackberry.nfc.isNFCSupported()
Not all BlackBerry devices include NFC support. This function returns true iff the device the code is running on supports NFC.
ndefMessageReceived(ndef_message)
To be able to receive NDEF messages of a given type when detected, you must implement a JavaScript function which can accept a single parameter as shown. You must supply the name of this function to your invocation of the blackberry.nfc.ndef.register_ndef function. In our example, the name used is ndefMessageReceived but you can choose your own function name. You may also register a different function for each registered NDEF record type or use the same function for all types, the choice is yours.
On detecting an NDEF message of the registered type, the extension will make a call back to the named JavaScript function, passing the NDEF message as a string variable.
The string is a JSON formatted representation of the NDEF message which your application may then process according to its requirements.
onNdefError(error_message)
Errors which occur whilst processing an NDEF message will be reported via a call back to the call back error function that was specified when registering for the NDEF message type. Here we used the name onNdefError but you can choose your own name.
The “index.html” page uses window.onload to initialise itself. Its code is probably best read to be understood. It will check for NFC support and availability, complain if there is none, otherwise register the default listeners. It will also toggle some field visibilities so that the UI makes sense.
The WebWorks NFC NDEF Extension
You should already be familiar with the concept and practice of implementing WebWorks extensions. If you’re not, it is suggested that you review the following documentation from the BlackBerry HTML5 and WebWorks microsite:
This sample WebWorks application has been developed against BlackBerry WebWorks Smartphone SDK version 2.3.1.5 which was the most recent version at the time of the writing of this article.
The “src” directory of the extension project (see Figure 3) contains a number of Java classes contained within a package called “widgetpackage”. It also includes an XML file called “library.xml” which defines the feature ID to be used from within JavaScript as the prefix to API methods exposed by the extension and the Java class which implements the “WidgetExtension” interface.
We’ll describe each of the classes and interfaces next.
For those people in a hurry however, those classes whose names begin with “Function” implement the three API functions:
Simple! J
Figure 5 - The NfcExtension project source
Here is a brief description of the objects as shown in the project in Figure 3
|
Item |
Description |
|
Constants |
This contains the definitions of various constant String variables.
|
|
FunctionInitLogging |
This is a sub-class of ScriptableFunction that implements the “init_logging” function and switches on the logging to the event log.
It achieves this by making the following call:
Utilities.initLogging(log_id, app_name);
Note that you can supply your own “app_name” value as an argument when you call this JavaScript.
If you do not, a default value of “NfcExtension” is used and this becomes the application name you will see in the BlackBerry event log viewer.
|
| FunctionIsNfcAvailable |
This is a sub-class of ScriptableFunction that is used to see if NFC is currently available. This of this as permission from the user (via “Manage Connections” and/or other security dialogues). |
| FunctionIsNfcSupported | This is a sub-class of ScriptableFunction that is used to see if NFC is supported. Think of this as a hardware check. |
|
FunctionRegisterNdefListener |
This is a sub-class of ScriptableFunction that implements the “register_ndef” function. It accepts as parameters, a mandatory JavaScript function which will be called to deliver ndef messages, a second mandatory JavaScript function which is used for reporting errors and optionally, a third optional parameter which may specify an NDEF record type or a JSON message containing a “type” and “typeNameFormat”. In the absence of the third, optional parameter, a default value of “Sp” (the official designation of a Smart Poster from the NFC Forum) is applied. Note though, that for the moment, the sample code supports only “Sp” (smart poster). This means that you should not use other record type values unless you are also prepared to enhance the NdefMessageParser so that it supports your type.
|
|
FunctionRegistry |
Maintains a register of NDEF record types and associated call back functions. |
|
FunctionUnregisterNdefListener |
This is a sub-class of ScriptableFunction which implements the “unregister_ndef” function. Its type parameter behaves the same as FunctionRegisterNdefListener.
|
|
NdefJavaScriptBridge |
This class is a singleton whose purpose is to pass a parsed NDEF message in JSON format back up to the JavaScript in our WebWorks application where it can be acted upon.
Its method “useNDEFMessage” is called by the NDEFMessageParser and receives the parsed NDEF message as a JSON string.
It then communicates the JSON string to the WebWorks application by invoking the ScriptableFunction object obtained from the FunctionRegistry singleton for the relevant NDEF record type.
Similarly, its reportError function looks up the error reporting call back function for a specified record type and calls it to report errors up to the web application layer. |
|
NdefMessageParser |
This is a simple parser which extracts ‘any’ type of NDEF message from a smart poster NDEFthe message from the message received from by the NFC interface.
|
|
NfcExtension |
This implements the WidgetExtension interface.
|
|
ScriptableNdef |
Our WebWorks extension must include a class which extends Scriptable and maps the individual API function names of “register_ndef”, “unregister_ndef” and “init_logging” to the classes which implement their logic.
|
| ScriptableNfc | Our WebWorks extension must include a class which extends Scriptable and maps the individual API function names of “isNFCAvailable” and “isNFCSupported” to the implementing classes. This class also has the field “ndef” to offer access to ScriptableNdef. |
|
Utilities |
A simple “utility” class which contains various static methods including those concerned with logging to the event log.
|
| URLPrefixes |
This class is a collection of constants for decoding the standard NDEF URI prefixes. NDEF specifications state that URLs are transmitted for a very basic compression. URIs generally start with a very small number of prefixes so it is easy to compress them. For example “http://www.” is 11 bytes of text – but can be sent in 1 byte thanks to these prefixes. |
|
WidgetNdefMessageListener |
This implements the NDEFMessageListener interface. It is here that NDEF messages are initially delivered by the NFC sub-system.
On receipt of a call back to its onNDEFMessageDetected() method, it invokes the parseAndDeliver() method of the NdefMessageParser, resulting in the message being parsed and converted into a JSON string which is then delivered via the NdefJavaScriptBridge to our JavaScript code.
NdefMessageParser.getInstance(message).parseAndDeliver(message);
|
Here's an example of the full JSON message as received by the WebWorks application from the extension:
{
"uri":"http://www.thenedoko.com",
"url":"http://www.thenedoko.com",
"text":"The Nedoko",
"textValues":[
{
"id":"",
"type":"T",
"typeNameFormat":1,
"payload":[
2,101,110,84,104,101,32,78,101,100,111,107,111
],
"languageCode":"en",
"value":"The Nedoko"
}
],
"id":"",
"type":"Sp",
"typeNameFormat":1,
"records": -- removed for clarity --,
"payload":[ 145, 1, . . . -- removed for clarity -- ]
}
Let’s look at each element – note that the ordering is not significant.
|
"uri":"http://www.thenedoko.com", |
The uri of a SmartPoster. The uri field was added to match the naming used in NDEF documents. The url field remains for backwards compatibility. |
| "text":"The Nedoko", | This is the text of the first element of text found in the SmartPoster |
|
"textValues":[ |
This is an array of ALL text elements found in the SmartPoster. Your application can iterate through the array and chose the most appropriate for your user based on the languageCode. |
| "id":"", | The id of the record. |
| "type":"Sp", | The type of the record. For an NDEF SmartPoster, this will be “Sp”. |
| "typeNameFormat":1, | The typeNameFormat of the record. For an NDEF SmartPoster, this will be 1. |
|
payload":[ 145, 1, 14, 85, 1, 116, 104, 101, 110, 101, 100, 111, 107, 111, 46, 99, 111, 109, 81, 1, 13, 84, 2, 101, 110, 84, 104, 101, 32, 78, 101, 100, 111, 107, 111 ] |
This is an array of numbers which are the actual bytes that were contained in the payload of the NDEF record. In general, there’s no reason to read these. If you want to parse your own content though – accessing payload is your start point. |
The Fake button in the GUI sends a very small (and badly drawn) image. It is in a MEDIA record. Here’s what the JSON looks like:
{
"records": -- removed for clarity --
"id":"",
"type":"image/bmp",
"typeNameFormat":2,
"payload":[ 67, 77 -- removed for clarity -- ],
"mimeType":"image/bmp",
"body":"Qk1+AAAAAAAAAD4AAAAoAAAAEAAAABAAAAABAAEAAA -- removed for clarity --",
"dataURI":"data:image/bmp;base64,Qk1+AAAAAAAAAD4AA
}
| "type":"image/bmp", | This is a MIME type that we registered for. The sample application registers for several common image types. The typeNameFormat |
| "typeNameFormat":2, | The type name format is MEDIA (2). |
| "mimeType":"image/bmp", | This field is added for convenience reasons by the parser, it is the same as type. |
| "body":"Qk1+AAAAAAAAAD4AAAAoAAAAEAAAABAAAAABAAEAA |
This is a Base64 encoding of the payload of the record. |
|
"dataURI":"data:image/bmp;base64,Qk1+AAAAAAAA…" |
This is a data URI which uses the Base64 encoding in body. In the sample application, this dataURI is used to populate an <IMG> |
Records…
You can use the extension without caring at all about its use of records, but here’s how it works and what it does.
The records element was removed above – for clarity. The records element reveals the NDEF structure;
The current message parser does the following;
Future Evolution of the Extension
The code for the WebWorks extension described in this article is available from our GitHub repository. We’d love to see contributions from the community which result in the extension becoming more fully functional and useful. The version presented here supports tag reading but does not support tag writing. Nor does it support other aspects of NFC. There’s a lot we could do together.
As far as NDEF tags are concerned, we believe there to be no reason to design a JSON structure to represent NDEF messages. That work has already been done by the NFC Forum. What we need from our Web Works extension is a way to deliver that same structure in a JSON format. Just our $0.02. What do you think?
Summary
This article should have demonstrated how easy it is to exploit NFC from a WebWorks application.
The place to go for more information on the BlackBerry WebWorks SDK is here:
https://bdsc.webapps.blackberry.com/html5/
BlackBerry Java APIs are documented here if you'd like to browse further: http://www.blackberry.com/developers/docs/7.0.0api
Source code for the WebWorks NFC extension described in this article is in the following GitHub repository:
https://github.com/blackberry/WebWorks-Community-A
And finally, the sample application can be found embedded in the page here:
https://github.com/blackberry/WebWorks-Community-A
See the NFC Article Index for the list of other articles in this series