If you want to publish your web apps through the big device app stores—such as the Apple App Store, Google Play, or the Windows Store—you need to create a hybrid app. These apps are similar to packaged apps in that all their resources are contained in a single archive, but they go one step further by adding a native shell, or wrapper, around the files, which ensures that the app can be integrated into the main operating system, providing security and better performance and also allowing access to restricted device APIs. A number of software solutions exist for making hybrid apps, but one of the most common—and certainly the easiest to learn—is PhoneGap.
Although owned by Adobe, a commercial entity, PhoneGap is free, open source software that allows you to build semi-native mobile applications using web platform technologies. PhoneGap is a distribution of software called Apache Cordova, which used to be called PhoneGap before it was sold to Adobe and things became complicated. The names are often used interchangeably, but I’ll stick to calling it PhoneGap for consistency’s sake.
PhoneGap works across multiple platforms, chief among them iOS, Android, and Windows Phone, and one of its major selling points is that, as it’s a native OS wrapper around web platform code, it allows access to APIs on a device that are not always available through the browser. For this, it uses its own API, which matches standard APIs from each device where present, acts as a bridge when devices have differing implementations of an API, and otherwise creates new methods and objects where necessary.
To set up PhoneGap, you need to download the SDK for each device you want to target and, in some cases (notably for iOS), also get a developer certificate. When you’ve done all this, you complete the setup for each environment (full instructions are on the PhoneGap website, linked to in Appendix K) and start a new project, which creates a folder structure with a few key files, including the ones necessary for access to the API.
Once your setup is complete, you can add all the files to the project that your app needs to run, and then begin to take advantage of the PhoneGap API. Some of the properties in the API require that you add permission requests to a manifest file because (as I mentioned earlier) PhoneGap uses the XML-based widgets specification for requests. For example, to request access to the Notification API, you include the following XML element in the file config.xml:
<plugin name="Notification" value="org.apache.cordova.Notification"/>
Some platforms require no extra permissions, or make some methods available without requiring permissions, whereas others insist on permission requests for all methods. The API documentation has full details.
The PhoneGap API is largely composed of a series of properties and methods on the navigator object. Some of these properties are already available through browsers. When they are, as with the geolocation object you learned about in Chapter 6, PhoneGap’s API chooses the native implementation first, falling back to its own implementation on systems where the property is not available.
Other properties require heightened permissions and, as such, are available on some platforms exclusively through PhoneGap. For example, consider the contacts object, which provides access to the user’s contact list—not something you want exposed to the Web without special authorization.
The contacts object has two functions: create() and find(). To select items from the contacts list, you use the latter with two required arguments: contactFields (a list of fields to return) and contactSuccess (a function to be run when a successful query takes place).
In the following code, I set up a query to get the display name and birthday of all contacts in the address book; then if this query is successful, it runs an anonymous function. This function loops through all of the results (in the contacts object I defined) and adds them to a string called contactDOB, which I use here to populate a list.
navigator.contacts.find(['displayName','birthday'], function (results) {
var i, contactDOB;
for (i=0; i < results.length; i++) {
contactDOB += '<li>' + results[i].displayName + '(' + results[i].
birthday + ')</li>';
}
});
Future browsers and web-based operating systems (such as Firefox OS) will probably provide direct access to some of these methods in the future, meaning the long-term future of PhoneGap will likely be in polyfilling features on legacy devices. PhoneGap’s developers are cognizant of this, as stated clearly in a blog post called “Beliefs, Goals and Philosophy”:
The ultimate purpose of PhoneGap is to cease to exist.
In addition to its device properties API, PhoneGap also has a number of extremely useful events that register changes to the device’s status, from its network status and capability to the battery level. These events are critical if you want your app to provide users with the best possible experience, such as ensuring data is saved before a battery runs out or when network connection is lost.
The most important event is deviceready, which fires when PhoneGap has fully loaded and is ready to execute. The deviceready event is functionally identical to the DOMContentLoaded event you saw in Chapter 5 in that it also should be used in every script to ensure that all required libraries have been loaded and are in place before the rest of the scripts are run. As such, all of your functions that require access to the PhoneGap API should be run in the callback function:
document.addEventListener('deviceready', function () {
// All PhoneGap-related functions
}, false);
Other events include pause and resume. The former is fired when the current application is closed and moved to a background process, and the latter when it becomes active again. For example, you may want to store data when the application is moved to a background process to make sure users doesn’t lose their work:
document.addEventListener('pause', function () {
// Backup data
}, false);
Some events fire when an application disconnects or reconnects from a network (offline and online); when the volume or call buttons are pressed (volumedownbutton, volumeupbutton, startcallbutton, and endcallbutton); and when the battery status changes (batterystatus detects changes in status, whereas batterylow and batterycritical fire when the battery is low or in a critical state, as defined by the device).
Another popular approach to publishing hybrid mobile apps is Appcelerator Titanium. Rather than acting as a wrapper around a web app like PhoneGap, Titanium is an SDK that lets you develop applications with JavaScript using native UI elements from the target device platform. This approach has the advantage of making your app look and feel more like a native app, but it requires that you write it in a way that isn’t compatible with the standard open web platform approach.
For that reason, I won’t cover Titanium further in this book, although knowledge of its existence is useful.