PhoneGap is a development framework that allows you to build apps for iOS, Android, BlackBerry, Windows Phone 7 and 8, Symbian, and Bada all using (mostly) HTML5 and JavaScript. The folks at PhoneGap have created what is essentially a basic browser application, but with no interface. You implement the interface in HTML5 and JavaScript, then compile the app for your given platform. They’ve also developed a system for plug-ins so that developers can extend the basic browser application using native features of the various platforms. It’s handy because it means you don’t have to know the native application frameworks for the various mobile platforms in order to write applications that can run on them all.
For this book, you’ll be using PhoneGap to write apps for Android and a plug-in that allows you to access the NFC hardware that’s built into many Android phones. The code you write to listen for tags and to interact with the user will be written in JavaScript and the interface will be laid out in HTML5. The application shell is written in Java, as is the NFC plug-in, but you won’t have to change any of the shell code for the projects in this book.
PhoneGap-NFC also supports Windows Phone 8, BlackBerry 7, and BlackBerry 10. We chose Android for this book because it has the largest market share and the most NFC phones, and most users of the PhoneGap-NFC plug-in have been Android users. If you have a Windows Phone or BlackBerry, you should be able to modify some of the examples to follow along. However, there are some limitations. Windows Phone 8 can read, write, and share NFC tags, but only has access to the NDEF data. It can’t see tag type, tag UIDs, or any other tag metadata. BlackBerry 10 has similar restrictions: it can read and share NFC tags, but currently cannot write them.
PhoneGap-NFC for BlackBerry 7 supports more NFC features than BlackBerry 10, but you’ll need to use older releases to make it work since PhoneGap 3.0 dropped support for BlackBerry 7.
You can use any text editor you want to write your code, but you’ll use the Android software development kit (SDK) and its associated tools to compile your code and deploy it to your device. You’ll also get to know the Cordova command-line interface (CLI), which is a set of tools for compiling PhoneGap applications using the Android SDK. You’ll need a little familiarity with the command-line interface of your computer as well.
The instructions assume you’re working in a command-line interface, such as the Terminal on any Linux machine or OS X. For Windows users at the Command Prompt, there are some slight differences that we’ll call out.
For the projects in this chapter, you need:
First you need to download the Android SDK from the Android Developer site. Android recommends that you download the Android Developers Toolkit (ADT) bundle, which includes a bundled version of the Eclipse development environment. We’re not using Eclipse for this book, however, so you can just download the SDK tools for your platform, which should take less time to download. To do that, click “Use an Existing IDE” at the bottom of the “Download” page and you’ll get a link to download just the SDK tools without Eclipse.
You’ll need to install a Java Development Kit (JDK) first by downloading it from the “Java SE” link on the Oracle website. After you install Java, you can run the Android SDK installer.
You’ll need one more thing on Windows: Apache Ant, which manages the build process for Android programs. Download the Ant ZIP file from the Apache Ant website, extract the file to the C: drive, and rename the top-level folder (such as apache-ant-1.9.1-bin) to Ant. If you did this correctly, you should find subdirectories such as C:Antin and C:Antlib.
On Windows, the Android SDK installer will default to a hidden directory in your home directory: C:UsersUsernameAppData LocalAndroidandroid-sdk, which will make it hard to find later. We suggest you change this to C:UsersUsernameAndroid android-sdk.
Open up a Terminal window and change directories to the SDK directory (i.e., use cd /Applications/android-sdk-macosx
). The SDK doesn’t come with a version of the Android platform tools, so you need to install them by typing the following:
$
tools/android update sdk --no-ui
If the Android SDK installer can’t find your Java installation (a common problem on 64-bit Windows), quit the installer, and set your JAVA_HOME
environment variable as directed later in this section. Try the installer again and it should find your Java installation.
You’ll be given the opportunity to install the tools when the installer is finished. Leave the checkbox labeled “Start SDK Manager” checked and click “Finish.” When the SDK manager appears, click “Install n Packages” (where n is whatever number of packages happen to be offered by default). If you accidentally unchecked the checkbox before clicking “Finish,” open a Command Prompt, change directory to the SDK location (i.e., cd Androidandroid-sdk
) and run the following command:
C:UsersUsernameAndroidandroid-sdk>
tools
android update sdk --no-ui
This will update the Android SDK and install the latest versions of the platform tools. You may be asked to accept some software licenses before you proceed. This will take a while, so you may want to take a minute to stretch and get some refreshment while it’s installing.
Next you need to change the PATH
variable for your environment to include the Android SDK tools. The tools directory covers most of the tools for compiling, uploading, and running your app on your device, and in platform tools, you’ll find an important tool called adb
that you’ll use for debugging purposes later.
In the examples that follow, if you put the tools in a location other than the one shown, change the paths as needed. Also note that you are creating two paths: one for the tools subdirectory and one for platform tools.
export
ANDROID_HOME
=
/Applications/android-sdk-macosxexport
PATH
=
$PATH
:$ANDROID_HOME
/tools:$ANDROID_HOME
/platform-tools
Change the ANDROID_HOME path if you stored the SDK somewhere other than the Applications directory, of course. Then save your profile file, and log out of the Terminal and log back in to reset the PATH
variable.
You have to find your way to the “System Properties Advanced” dialog box:
Click the button at the bottom labeled “Environment Variables.” Find the PATH
entry under “User Variables” (not “System Variables”) and click “Edit.” If there is no PATH
entry, click “New” and name the new variable PATH
.
Append all three of the following to the end of the path with no space between them (the last two entries let you run Java and Ant from the command line):
;%ANDROID_HOME% ools ;%ANDROID_HOME%platform-tools ;%JAVA_HOME%in ;C:Antin
Be sure to include the ;
separator as shown (if you had to create a new PATH
variable, you can skip the leading ;
). Don’t change anything that’s already there: you must add this to the end. If you make a mistake, click “Cancel” and try again. Stay out of the “System Variables.” If you make a mistake in the system PATH setting, you can cause serious problems for Windows.
While you’re on this screen, you must also set your ANDROID_HOME
and JAVA_HOME
environment variables:
JAVA_HOME
and the value to C:Program FilesJavajdk1.7.0_25
(or whatever the installation directory of your JDK is).
ANDROID_HOME
and the value to C:Users\%USERNAME%Androidandroid-sdk
.
If you installed Java or the Android SDK in a different location, change the variables as necessary.
Node.js is a platform for developing network applications in JavaScript. It also has a great system for installing packages (such as PhoneGap). Node’s package manager (npm) is the fastest way to install the Cordova CLI for PhoneGap. You’ll also see Node used in projects in Chapters 7 and 9.
To install Node.js:
If you have any trouble running Node from the command line in Windows after you install it, you may need to log out and log in again for its PATH changes to take effect.
sudo apt-get install nodejs npm
.
export
PATH
=
/usr/local/share/npm/bin:$PATH
You’ll also need Git installed. It’s installed by default on OS X and most Linux distributions. If not, install it with your package manager. You can get command-line Git for Windows, and the Git installer will ask if you want to install Git into the system PATH environment variable. We suggest that you do so, because this will let you run Git from the Command Prompt.
Open a Terminal or Command Prompt and install the Cordova package (this gives you the PhoneGap framework).
$
npm install -g cordova
> npm install -g cordova
The -g
option installs the Cordova command-line utility to a location in your PATH.
You can now create a PhoneGap project just by typing the following:
cordova createproject-location
package-name
app-name
In the command, project-location
is the path to your new Cordova Android project, package-name
is the package name for the app you’ll create, using reverse domain-style notation (e.g., com.example.myapp), and app-name
is the name of your application.
You’ll then need to cd
into the project directory and add the Android platform:
cd /path/to/project-location
cordova platform add android
You’ll see these steps frequently in the chapters that follow. For most of this book, we’ll refer to the preceding steps simply by saying “use the cordova create
command to create a project.”
Change directories to whatever directory you like to keep projects in (perhaps your Documents directory) and use the cordova create
command to create a project:
$
cordova create ~/Hello com.example.hello Hello
There is no output from create
if it succeeds, but it will create a new directory. This command will create a directory in your working directory called Hello. Change directories to it and list the files:
$
cd
~/Hello$
cordova platform add android$
ls
If Cordova requests that you install a specific Android target (other than the ones that were installed by default), type android
to start the SDK manager, then install the SDK that Cordova requested. The version numbers of the SDK may not always match up (e.g., Cordova may ask for the Android 4.2 SDK, but the SDK manager only offers you 4.2.2), but the Android target that Cordova asks for (e.g., target 17) will match the API number listed in the SDK manager, as in Android 4.2.2 (API 17). After you install the Android target, try running the cordova create
command again.
On Windows, the commands will be a little different. Open a Command Prompt (by default, it will place you in your home directory, usually C:Usersusername
), but to be sure, you might want to change directory to it first with cd /D %userprofile%
(in most configurations, the %USERPROFILE%
environment variable contains your home directory). You can, of course, run these commands in another working directory:
>
cd
/D
%userprofile%
>
cordova
create Hello com.example.hello Hello>
cd
Hello>
cordova
platform add android>
dir
On all three platforms, the directory will contain the following structure:
The platforms/android directory contains the following:
On Windows, you may need to install a USB driver for your device. When you updated the SDK earlier, you got USB drivers for many devices. However, even flagship devices like the Nexus 7 may require a separate driver installation. For example, you can download the Nexus 7 driver from ASUS. See Android’s USB Drivers page for instructions on installing drivers that are included with the Android SDK.
You’ve got everything you need here to run a very basic app that does nothing but display a splash screen. To compile and install it on your device, connect the device over USB and run the following command if you are on OS X or Linux:
$
cordova run
If you’re on Windows, run this command:
>
cordova
run
When everything’s ready, you’ll be running your app directly on your Android phone or tablet.
Can’t find developer options on Android version 4.2 or later? Open “Settings” and scroll down to “About Device” (it’s “About Tablet” on the Nexus 7). Tap the “Build” number seven times. This will enable developer options. Then return to the previous screen to find “Developer Options” and turn it on. In particular, you want to enable “Stay Awake” while charging and “USB Debugging.” If you have a password set for your device, you may want to disable it while you’re coding, as it removes the need to unlock your device every time you upload a new version of your app.
Finally, open the phone and launch the Hello Application. You should see a screen like that in Figure 3-1. Once you’ve got the basic “Hello, World!” application running, try modifying the index.html to make it more fancy. It lives in the www directory. Add buttons, images, and all the other things you’d add to an HTML page. Then save your files, run it again, and see how it changes on your phone.
There are two files you’ll work with frequently in your PhoneGap projects: the index.html in the www directory, and the index.js file in the www/js directory. You can add other HTML and JavaScript files, but by convention, these will be the root of your application. These are the files you’ll modify to make your app do what you want.
The index.html page will include the graphic layout of your application, just as it would for any website. The index.js contains event handlers, like onDeviceReady()
, initialize()
, and so forth. Later on you’ll add some functions to it, like onNfc()
for when a tag is read.
You can always get an unmodified version of the default file structure by creating a new project.
There are a few other JavaScript files that affect your application that you’ll likely never see: the cordova.js file, the cordova_plugins.js file, and its companion, the cordova_plugins.json file. The cordova.js file is the main PhoneGap library. The cordova_plugins.js and cordova_plugins.json files initialize the plug-ins you install, giving you access to the PhoneGap-NFC library and the NFC hardware. These show up in platforms/android/assets/www when you install plug-ins and run your app.
Since the “Hello, World” template is such a handy reference, keep it intact and make a new project for your first custom app. This project will contain the bare minimum you need in your HTML and JavaScript files to get things running. To make it interesting, you’ll make an app that starts and stops tracking your latitude and longitude on a click.
In the following examples, OS X and Linux (indicated by a leading $
) and Windows (indicated by a leading >
) variants of the commands are shown one after another. On Windows, we’re using %userprofile%, which points to your home directory in most Windows installations, but you can use another location if you wish.
In future chapters, unless the commands are radically different, we’ll only show the OS X and Linux version, and Windows users should assume the commands are differentiated as shown here.
Make a new project called Locator just as you did before. Use cordova create
again:
$
cordova create ~/Locator com.example.locator Locator
Then add the Android platform and the geolocation plug-in to the project. Plug-ins for PhoneGap/Cordova extend the framework’s functionality. Plug-in authors register their plug-ins’ URLs with the Cordova project so they can be added to the plug-in database. Many plug-ins add access to a device’s hardware, like this one, which gives you access to a device’s geolocation system. The NFC plug-in, which you’ll see shortly, gives you access to the NFC radio. You’ll see how plug-ins fit into the file structure a bit later, but for now, here’s how to install the geolocation plug-in:
$
cd
~/Locator$
cordova platform add android$
cordova plugin addhttps://git-wip-us.apache.org/repos/asf/cordova-plugin-geolocation.git
Now change directories to the project’s www directory. Edit the index.html file and delete everything. The following is a minimal HTML file that includes only the basics you’ll use for most apps. There’s a main div element called app
where all the action will take place. You’ll see it and its subelements modified quite a bit in the index.js file. At the end of the file, include the cordova.js script and your application’s index.js script. Finally, call the initialize()
function from index.js to run the app:
<!DOCTYPE html>
<html>
<head>
<title>
Locator</title>
</head>
<body
style=
"font-size: 1.4em;"
>
<div
class=
"app"
>
<div
id=
"messageDiv"
></div>
</div>
<script
type=
"text/javascript"
src=
"cordova.js"
></script>
<script
type=
"text/javascript"
src=
"js/index.js"
></script>
<script
type=
"text/javascript"
>
app
.
initialize
();
</script>
</body>
</html>
Edit the index.js file and delete everything. You’ll replace it with the following script. All the functions and variables in this script are local to an object called app
, by convention. Start out by initializing a variable called app
:
var
app
=
{
};
Next, add a few functions you need for initialization, to set up listeners for startup events, button touches, and the like. Replace the code you just added with this:
var
app
=
{
/*
Application constructor
*/
initialize
:
function
()
{
this
.
bindEvents
();
console
.
log
(
"Starting Locator app"
);
},
/*
bind any events that are required on startup to listeners:
*/
bindEvents
:
function
()
{
document
.
addEventListener
(
'deviceready'
,
this
.
onDeviceReady
,
false
);
},
/*
this runs when the device is ready for user interaction:
*/
onDeviceReady
:
function
()
{
app
.
display
(
"Locating..."
);
app
.
watchLocation
();
},
Next, add a function to get the device’s location. This function has two callbacks, one for success and one for failure. If it succeeds, it displays the device’s coordinates using a function called display()
. If it fails, it displays a failure message:
/*
Displays the current position in the message div:
*/
watchLocation
:
function
()
{
// onSuccess Callback
// This method accepts a `Position` object, which contains
// the current GPS coordinates
function
onSuccess
(
position
)
{
app
.
clear
();
app
.
display
(
'Latitude: '
+
position
.
coords
.
latitude
);
app
.
display
(
'Longitude: '
+
position
.
coords
.
longitude
);
app
.
display
(
new
Date
().
toString
());
}
// onError Callback receives a PositionError object:
//
function
onError
(
error
)
{
app
.
display
(
error
.
message
);
}
// Options: throw an error if no update is received every 30 seconds.
//
var
watchId
=
navigator
.
geolocation
.
watchPosition
(
onSuccess
,
onError
,
{
timeout
:
30000
,
enableHighAccuracy
:
true
});
},
Finally, you need to connect these functions to the user interface. The functions that follow, display()
and clear()
, write to an HTML div
element in index.html. You’ll see these same two functions in many apps in this book:
/*
appends @message to the message div:
*/
display
:
function
(
message
)
{
var
label
=
document
.
createTextNode
(
message
),
lineBreak
=
document
.
createElement
(
"br"
);
messageDiv
.
appendChild
(
lineBreak
);
// add a line break
messageDiv
.
appendChild
(
label
);
// add the text
},
/*
clears the message div:
*/
clear
:
function
()
{
messageDiv
.
innerHTML
=
""
;
}
};
// end of app
The full source listing for this application can be found on GitHub.
Save the files you edited, then cd
to the project root, and run the app on your phone with the following commands:
$
cd
Locator$
cordova run
>
cd
/d
%userprofile%
Locator>
cordova
run
When you run the app on the phone, you’ll get a screen as shown in Figure 3-2.
You can modify the HTML and JavaScript just as you would for any other HTML-, JavaScript-, or CSS-based application on the Web. So feel free to experiment. Once you understand the basics of making a PhoneGap app, you’re ready to move on.
Now that you’ve got a handle on PhoneGap, it’s time to extend it to include the NFC plug-in. For this you’ll need the same software as the first app, the PhoneGap-NFC plug-in, and a few NFC tags as well. The first NFC app you create will read just the unique ID of any tag it sees.
The same structure will be used for all PhoneGap apps, so keep this app handy to use as a template. Create a new app called NfcReader
:
$
cordova create ~/NfcReader com.example.nfcreader NfcReader$
cd
~/NfcReader$
cordova platform add android
There are a number of changes needed to add NFC support to your project. These are all automated by the command:
$
cordova plugin add /path/to/plugin
The one you’ll use commonly throughout the book is:
$
cordova plugin add https://github.com/chariotsolutions/phonegap-nfc.git
So you understand what’s going on under the hood, here’s what’s installed:
The file platforms/android/res/xml/config.xml gets modified as well. Here are the modifications to those two files:
<feature
name=
"NfcPlugin"
>
<param
name=
"android-package"
value=
"com.chariotsolutions.nfc.plugin.NfcPlugin"
/>
</feature>
The AndroidManifest.xml file gets the NFC permission added at the end of the other permissions tags:
<uses-permission
android:name=
"android.permission.NFC"
/>
<uses-feature
android:name=
"android.hardware.nfc"
android:required=
"false"
/>
Since that’s a lot to remember, it’s nice that the one-line plug-in add
command does it all for you.
You’ve already created your project using the create
command, as directed earlier. Next, change directories to the root of your project and add the plug-in as described at the beginning of this section like so:
$
cd
~/NfcReader$
cordova plugin add https://github.com/chariotsolutions/phonegap-nfc.git
>
cd
/d
%userprofile%
NfcReader>
cordova
plugin add https://github.com/chariotsolutions/phonegap-nfc.git
This installs the NFC plug-in from its online repository in the current working directory.
Now that you’ve got all the assets in place, it’s time to make the application itself. You’ll have two files you need to edit for this project:
This app will listen for NFC-compatible RFID tags and print their IDs on the screen.
Start with index.html as before. Here’s a bare-bones page, much like the Locator app’s index page. The changes are that you’re adding a call to the Cordova script at the end of the body and you’re changing the elements of the app div in the body. The latter is where tag IDs will be displayed.
Open index.html and replace it with the following code, then save the changes:
<!DOCTYPE html>
<html>
<head>
<title>
NFC tag ID reader</title>
</head>
<body
style=
"font-size: 1.5em"
>
<div
class=
"app"
>
<div
id=
"messageDiv"
></div>
</div>
<script
type=
"text/javascript"
src=
"cordova.js"
></script>
<script
type=
"text/javascript"
src=
"js/index.js"
></script>
<script
type=
"text/javascript"
>
app
.
initialize
();
</script>
</body>
</html>
The index.js file will have an event handler to listen for NFC tags and rewrite the message div when it gets a tag. As before, start by initializing the app variable, and adding an initialize()
function and a bindEvents()
function:
var
app
=
{
/*
Application constructor
*/
initialize
:
function
()
{
this
.
bindEvents
();
console
.
log
(
"Starting NFC Reader app"
);
},
/*
bind any events that are required on startup to listeners:
*/
bindEvents
:
function
()
{
document
.
addEventListener
(
'deviceready'
,
this
.
onDeviceReady
,
false
);
},
The onDeviceReady()
function is a bit more complex this time. You need to add a listener for when tags are discovered by the NFC reader. The nfc.addTagDiscoveredListener()
function tells the NFC plug-in to notify your app when any NFC tag is read. The first argument is the event handler that is called when a tag is scanned. The second and third arguments are the success and failure callbacks for the plug-in initialization. When it succeeds, it will call the onNfc()
function. When the listener is initialized, it’ll let you know, and when it fails, it’ll give you failure messages as well.
The addTagDiscoveredListener()
handler is one of a few different listeners you can use from the NFC library. It’s the most generic. It doesn’t care what’s on the tag, it just responds whenever it sees a compatible tag:
/*
this runs when the device is ready for user interaction:
*/
onDeviceReady
:
function
()
{
nfc
.
addTagDiscoveredListener
(
app
.
onNfc
,
// tag successfully scanned
function
(
status
)
{
// listener successfully initialized
app
.
display
(
"Tap a tag to read its id number."
);
},
function
(
error
)
{
// listener fails to initialize
app
.
display
(
"NFC reader failed to initialize "
+
JSON
.
stringify
(
error
));
}
);
},
The onNfc()
function takes the tag read in an NFC event and prints it to the screen using display()
, just as you saw in the Locator app. These are the last functions in the app:
/*
displays tag ID from @nfcEvent in message div:
*/
onNfc
:
function
(
nfcEvent
)
{
var
tag
=
nfcEvent
.
tag
;
app
.
display
(
"Read tag: "
+
nfc
.
bytesToHexString
(
tag
.
id
));
},
/*
appends @message to the message div:
*/
display
:
function
(
message
)
{
var
label
=
document
.
createTextNode
(
message
),
lineBreak
=
document
.
createElement
(
"br"
);
messageDiv
.
appendChild
(
lineBreak
);
// add a line break
messageDiv
.
appendChild
(
label
);
// add the text
},
/*
clears the message div:
*/
clear
:
function
()
{
messageDiv
.
innerHTML
=
""
;
}
};
// end of app
The full source listing for this application can be found on GitHub.
That’s all the changes. Save both files, then change directories to the root of the project if you’re not already there, and compile and install the application:
$
cd
NfcReader$
cordova run
>cd
/d %userprofile%N
fcReader > cordova run
This launches the NFC Reader application. When it’s up and running, bring a tag close to the phone, and you should get a message saying “Read tag” followed by the UID, in hexadecimal notation, as shown in Figure 3-4. Try with another tag and you’ll see another UID.
This will work with any RFID tag that’s compatible with your NFC reader. That includes all tags compatible with the ISO-14443A format, including Philips and NXP Mifare tags, Sony FeliCa tags, NXP DESFire. You’re not yet reading or writing data to the tag; you’re just reading the tag’s unique ID. For this application, compatible tags are not as much of an issue as when you start to write NDEF records to the tags. You’ll find that this app can read Mifare Classic tag IDs even on those devices that are supposedly incompatible with Mifare Classic.
You’ve proven that your device’s reader works, and can be programmed to read tags. In the next chapter, you’ll learn how to read from and write to tags using the NFC Data Exchange Format, NDEF.
If your app doesn’t read any of your tags, here are a few things to check:
The steps you followed in this chapter will be used in all of the PhoneGap-NFC projects that follow in this book, so here’s a quick summary to use for future reference:
cordova create
command
cordova platform
cordova plugin
Your app needs, at minimum, the following files:
Your index.html file needs to include the following JavaScript scripts:
Your main JavaScript file should include the following elements from the PhoneGap-NFC library:
If you’ve got all of those elements, you’re ready to go.
By now, you should be familiar with the structure of a PhoneGap app, and with the steps necessary to add the PhoneGap-NFC plug-in to an app. You’ll see this same structure replicated in the rest of the projects in this book. What you’ve seen so far, though, is really just RFID—there’s been no real NFC action yet. In the next chapter, you’ll learn about the data exchange format that defines all NFC transactions.