Building PhoneGap applications powered by Database.com

 

Requirements -

 

Additional required other products
Required products Sample files User level
Database.com account PhoneGap Build
Database.Com-PhoneGap-Sample
All

 

In this article we will explore the creation of mobile applications built using PhoneGap, with all data served and persisted using Database.com. Before we dive deeper into the technical details, let's review the terminology.
 
PhoneGap

 

PhoneGap is a free and open source technology that enables developers to create natively installed mobile applications on multiple platforms using traditionally web-based technologies. The best way to think of PhoneGap is a web view that takes up the device's full width and height. Within the web view, you build your application interface using HTML, CSS, and JavaScript.

 

The application web view
Figure 1. The application web view

 

The application's web view is based upon the native web view of the operating system, essentially the same as the standard web browser – minus the window chrome. You build all of the navigation and content elements entirely in HTML, CSS, and JavaScript, with your application logic written in JavaScript.

PhoneGap provides a JavaScript-to-native bridge. This lets your application interact with the native operating system without having to write any native code. You build your application logic entirely in JavaScript, and leverage the PhoneGap API to interact with the device operating system.

 

PhoneGap provides access to device features
Figure 2. PhoneGap provides access to device features

 

"Out of the box" PhoneGap provides access to a device's accelerometer, compass, and geolocation capabilities, access to device contacts, the local file system, the device camera, and media playback and capture functionality. You can access all of these features on multiple platforms, without having to write a single line of native code – all can be accessed entirely by JavaScript. If this isn't enough for you, you can easily extend PhoneGap by building "native plugins" on top of the extensible architecture – I'll get into further detail later in this article.

PhoneGap also provides a means of packaging applications to target popular mobile ecosystems. The output of a PhoneGap application is a binary application archive that contains all necessary HTML, CSS, & JavaScript assets for you application to function.

 

PhoneGap packages apps to target popular mobile ecosystems
Figure 3. PhoneGap packages apps to target popular mobile ecosystems

 

For iOS devices, this outputs an IPA file, for Android this is an APK file, for Windows Phone this is a XAP file, etc… All of these binary formats are normal archives that you could then upload to the iTunes Store, Google Play, BlackBerry App World, the Windows Phone Marketplace, or install directly onto a device. A single codebase for a PhoneGap application can be used to target Apple iOS, Google Android, Windows Phone, BlackBerry, HP WebOS, Symbain, and Samsung Bada operating systems, and can be used to target both phone and tablet form factors.

As I mentioned earlier, PhoneGap is free and open source. The entire codebase for PhoneGap is freely accessible as a part of the Apache Cordova project. You can download the source, make changes, and contribute back to the project today!

 

Database.com

Database.com is the cloud database offering from salesforce.com. Database.com enables hosted relational database capabilities that you easily can tap into within your applications, without having to manage the infrastructure on your own. You can use the Web-based administrative interface to create objects and relationships, and use the REST or SOAP APIs to access your data. You can learn more about the capabilities of Database.com through the Developer Center.

 

The Application

 

In this article, we will walk through the creation of a basic PhoneGap application that consumes data from Database.com.

Here is the basic concept: It is an application that could be used by workers "in the field" to travel to various locations and collect contacts or "leads". It can be used to gather contact information, as well as notes, and it can record the user's GPS coordinates to identify where the information was captured. It will also allow you to go back and edit data that you've previously captured. Of course, the application also needs to be accessible on a variety of platforms. Let's examine the basic flow, then we'll get into details how it was created.

 

The sample app three main screens
Figure 4. The sample app three main screens

 

You can see that there are three main screens, the "home" screen, which gives you the options to either add a new record or view existing records, the "Leads" list, which shows existing records, and the form to add/edit records. There will also be a login/authentication screen, which we will cover later, but for now you can see that it is a straightforward application use case.

The full source code for this application is available at https://github.com/triceam/Database.Com-PhoneGap-Sample.

 
Database

For data storage, this application will use a single custom table on Database.com. Although this is a basic one-table example, Database.com can also support large, multi-relationship data structures.

After you sign up for a free account, log in, and click "Create A New Object" on the System Overview screen.

 

Create a new object on the System Overview screen
Figure 5. Create a new object on the System Overview screen

 

This will show the "New Custom Object" dialog. Here's where you enter the label/name for your objects. Here I created an "Lead" object. To contain the leads that will be captured by the PhoneGap application.

 

Enter the label/name for your objects
Figure 6. Enter the label/name for your objects

 

The next step is to add custom fields to the "Lead" object. Under the "Custom Fields & Relationships" section, click on the "New" button to add data fields.

I added fields for "First Name", "Last Name", "Latitude", "Longitude", "Notes", "Email", and "Telephone". Just follow the steps in the online wizard – it will guide you through this process.

 

Add data fields under "Custom Fields & Relationships
Figure 7. Add data fields under "Custom Fields & Relationships

 

At this point, we've now created the data objects that will be used to persist data that is captured within the application. However, there is one more step before you can use these objects within a PhoneGap application. In order to access the data data remotely, you must create a remote access "application". The configuration of this application will include a unique key that will be used to correctly authenticate users and identify your data objects.

To create a new remote access "Application", just expand the "Develop" category and select "New".

 

Create a new remote access "Application" in the "Develop" category
Figure 8. Create a new remote access "Application" in the "Develop" category

 

This will display the "Remote Access Edit" form, where you will need to specify an application name, contact email, and callback URL configuration for your application. The application name will be used as descriptive text when logging into your application, and the callback URL will be used to redirect the user's browser once they have authenticated successfully.

 

Specify the application details in the Remote Access Edit" form
Figure 9. Specify the application details in the Remote Access Edit" form

 

Once you save this information, you will be provided with a "consumer key", which you will need later when logging in and accessing data services from Database.com. Make a note of your consumer key. You will need this later in your JavaScript configuration.

 

The "consumer key" for logging in and accessing data services from Database.com
Figure 10. The "consumer key" for logging in and accessing data services from Database.com

 

Once you have your consumer key, you're ready to start pushing and pulling data in and out of Database.com.

Forcetk.js

The application will communicate with Database.com's REST API using the forcetk.js JavaScript wrapper. Forcetk.js (Force.com JavaScript REST Tookit) is an open source wrapper to the REST API that simplifies the consumption of data from Force.com/Database.com inside of JavaScript-based applications. Forcetk.js provides the hooks for OAuth2 authentication, and helper methods that make retrieving and updating data incredibly easy.

When building applications in PhoneGap, you will be able to access the force.com REST API directly without need for a proxy (like you would if you were building a standard browser-based application).

 

The PhoneGap Application

When leveraging PhoneGap, you create your applications entirely in HTML, CSS, and JavaScript. You can develop these applications in any text editor. It is up to you to decide which approach to use. You can use a simple text editor like TextMate, an HTML editor like Dreamweaver, or a complex IDE like Xcode, Eclipse, or Visual Studio. IDEs like Xcode, Eclipse, or Visual Studio allow you to deploy PhoneGap applications directly onto a device using a USB connection. However, you can also use PhoneGap Build, a cloud-based PhoneGap compiler, which allows you to simply upload your HTML, CSS, and JavaScript code, and it will generate platform-specific binaries for you.

Because the application interface is being built using HTML, CSS, and JavaScript, it is possible to leverage existing tools and frameworks to improve developer productivity. This example will leverage the following tools to speed up the developer process:

  • Zepto.js – A development accelerator library that provides utility and shortcut functions for creating interactive and dynamic JavaScript experiences. Zepto.js has a jQuery compatible syntax, with a mobile-centric optimizations.
  • Twitter Bootstrap – A UI styling library that provides CSS styles and HTML/JavaScript components to make your application feel more like an "app" instead of "just a web page".
  • Mustache.js – An easy-to-use templating library that allows you to create HTML "templates" for use within your dynamic JavaScript applications. Templating enables you to easily separate your HTML UI layer from the application logic written in JavaScript.

The first thing to do within the application is create your root HTML file that will be the entry point into the application. All PhoneGap applications start with an "index.html" file, which is the "root" of the application. Within the index.html file, I included all of the appropriate libraries, with a blank HTML <body>. The HTML <body> is blank because the entire user interface will be created dynamically by JavaScript.

<html> <head> <link rel="stylesheet" href="assets/css/bootstrap.css" type="text/css" /> <link rel="stylesheet" href="assets/css/styles.css" type="text/css" /> <script type="text/javascript" src="js/libs/zepto.js"></script> <script type="text/javascript" src="js/libs/forcetk.js"></script> <script type="text/javascript" src="cordova-1.7.0.js"></script> <script type="text/javascript" src="js/libs/ChildBrowser.js"></script> <script type="text/javascript" src="js/libs/mustache.js"></script> <script type="text/javascript" src="js/salesforceWrapper.js"></script> <script type="text/javascript" src="js/application.js"></script> </head> <body></body> </html>

When a PhoneGap application is initialized, a "deviceready" event is dispatched. This event indicates that the contents of the application have been sufficiently loaded, and all PhoneGap APIs have been initialized.

document.addEventListener( "deviceready", onDeviceReady ); var sfw; function onDeviceReady( event ) { console.log("deviceready"); //initialize salesforce wrapper sfw = new SalesforceWrapper(); }

The first thing that the application does is initialize a JavaScript class that I created called "SalesforceWrapper". The SalesforceWrapper class wraps the forcetk.js library to streamline authentication, and includes all of the configuration information needed to access the force.com REST API. In this class, you'll need to set the clientID value with the consumer key that you obtained through the "Remote Access" configuration that was discussed earlier in this article.

function SalesforceWrapper() { /* AUTHENTICATION PARAMETERS */ this.loginUrl = 'https://login.salesforce.com/'; this.clientId = 'YOUR_KEY_GOES_HERE; this.redirectUri = 'https://login.salesforce.com/services/oauth2/success'; /* CLASS VARIABLES */ this.cb = undefined; //ChildBrowser in PhoneGap this.client = undefined; //forceTk client instance this.init(); } SalesforceWrapper.prototype.init = function() { this.client = new forcetk.Client(this.clientId, this.loginUrl); this.cb = window.plugins.childBrowser; } SalesforceWrapper.prototype.login = function (successCallback) { this.loginSuccess = successCallback; var self = this; self.cb.onLocationChange = function (loc) { if (loc.search(self.redirectUri) >= 0) { self.cb.close(); self.sessionCallback(unescape(loc)); } }; self.cb.showWebPage(self.getAuthorizeUrl(self.loginUrl, self.clientId, self.redirectUri)); } SalesforceWrapper.prototype.getAuthorizeUrl = function (loginUrl, clientId, redirectUri) { return loginUrl + 'services/oauth2/authorize?display=touch' + '&response_type=token&client_id=' + escape(clientId) + '&redirect_uri=' + escape(redirectUri); } SalesforceWrapper.prototype.sessionCallback = function(loc) { var oauthResponse = {}; var fragment = loc.split("#")[1]; if (fragment) { var nvps = fragment.split('&'); for (var nvp in nvps) { var parts = nvps[nvp].split('='); oauthResponse[parts[0]] = unescape(parts[1]); } } if (typeof oauthResponse === 'undefined' || typeof oauthResponse['access_token'] === 'undefined') { console.log("error"); } else { this.client.setSessionToken(oauthResponse.access_token, null, oauthResponse.instance_url); if ( this.loginSuccess ) { this.loginSuccess(); } } this.loginSuccess = undefined; }

The SalesforceWrapper class simplifies the example from forcetk.js, and enables you to authenticate with a single line of code in your application:

sfw.login( setupHomeView );

The login function of the SalesforceWrapper just needs a single parameter – a reference to a function that will be invoked once the user has successfully logged in.

You may have also noticed that the SalesforceWrapper refers to the ChildBrowser JavaScript class. The ChildBrowser class is part of the ChildBrowser PhoneGap native extension, which is available for iOS, Android, BlackBerry, and Windows Phone. This enables your PhoneGap application to have a "child" web view, which in this case, is used for authenticating the Force.com API.

Once the SalesforceWrapper class is initialized, the Moustache.js templates are initialized. Each template is a separate HTML file that will be used to render the interface, and they must be loaded into memory before they can be consumed.

var templates = { structure:"views/structure.html", home:"views/home.html", form:"views/formView.html", list:"views/dataView.html", listItem:"views/listItem.html", loaded: 0, requested: 0, }; function onDeviceReady( event ) { console.log("deviceready"); //initialize salesforce wrapper sfw = new SalesforceWrapper(); //load Mousetache HTML templates for (var key in templates) { (function() { var _key = key.toString(); if ( _key != "loaded" && _key != "requested" ){ templates.requested ++; var templateLoaded = function( template ){ onTemplateLoaded( template, _key ); } $.get( templates[ _key ], templateLoaded ); } })(); } } function onTemplateLoaded(template, key) { console.log( key + ": " + template); templates[ key ] = template; templates.loaded ++; if ( templates.loaded == templates.requested ) { setupDefaultView(); } }

Once the templates have been loaded, the setupDefaultView() function gets invoked. This sets up the initial user interface, based upon the templates.structure template.

var header, container; function setupDefaultView() { console.log("setupDefaultView"); $("body").html( templates.structure ); header = $("body").find("#header"); container = $("body").find("#content"); $('#login').tap(function (e) { e.preventDefault(); sfw.login( setupHomeView ); }); }

It then sets a reference to the "header" and "container" elements from that template for future usage, then adds an event handler to the "login" button so that when the user taps the button, the login functionality from the SalesforceWrapper class is invoked.

You can view the HTML fro the templates.structure template below:

<div id="header">Welcome</div> <div id="content"> <h3 style="padding-top:1.5em; padding-bottom:1.5em;" class="alert alert-info">Press the "Login" button to authenticate via Database.com.</h3> <br/><br/> <a id="login" class="btn btn-success">Login</a> </div>

Formatting is applied through CSS styles, and the rendered output is shown below. Once the user taps the "Login" button, the OAuth login screen for Database.com gets displayed.

 

The user taps Login and the OAuth login screen for Database.com displays
Figure 11. The user taps Login and the OAuth login screen for Database.com displays

 

All authentication is handled within the ChildBrowser, and is completely maintained by Database.com. As a developer, you don't have to worry about user account management or login functionality, as force.com handles this for you. The user simply must have permission to access your data objects (database) in Database.com. Once the user is successfully authenticated, the setupHomeView() function will be invoked, and will display the "Home" screen of the application.

The setupHomeView() function resets/clears the contents of the container element, and then fills it with the contents of the templates.home template and adds the appropriate event handlers.

function resetContainer() { //this removes child elements and cleans up event handlers container.children().remove(); container.removeClass("nopadding"); } function setupHomeView() { resetContainer(); container.html( templates.home ); header.html( "Welcome" ); $('#addNew').tap(function (e) { setupFormView(); e.preventDefault(); e.stopPropagation(); return false; }); $('#queryMyRecords').tap(function (e) { setupListView(); e.preventDefault(); e.stopPropagation(); return false; }); }

You can view the templates.home template below:

<h3>Please select an option:</h3> <a id="addNew" class="btn btn-info">Add New Record</a> <br/> <a id="queryMyRecords" class="btn btn-info">Query My Records</a>

On a device, the user will see the rendered output as shown below. As you can see, there are two buttons, one for adding a new record, and another to query existing records from Database.com.

 

The rendered output
Figure 12. The rendered output

 

Next, let's examine what happens when the user clicks on the "Add New Record" button. When the user clicks this button, the setupFormView() button will be invoked, which creates a new form for gathering data from the user.

function setupFormView(data) { resetContainer(); var html = Mustache.to_html( templates.form, data ); container.html( html ); currentLead = data; //request current location if ( !(data && data.Id) ) { header.html( "New Lead" ); navigator.geolocation.getCurrentPosition(onGeoSuccess, onGeoError ); } else { header.html( "Edit Lead" ); } $('#save').tap( saveFormData ); $('#cancel').tap( navigateBackFromFormView ); }

The setupFormView() function will clear the container element, and fill it with HTML from the templtes.form template. This is where you can see that templating become very useful. Next, let's examine the form template:

<div id="form"> <label for="first">First Name</label> <input id="first" type="text" value="{{First__c}}" /> <br/> <label for="last">Last Name</label> <input id="last" type="text" value="{{Last__c}}" /> <br/> <label for="phone">Telephone</label> <input id="phone" type="text" value="{{Telephone__c}}" /> <br/> <label for="email">Email</label> <input id="email" type="text" value="{{Email__c}}" /> <br/> <label for="notes">Notes</label> <textarea id="notes" type="text">{{Notes__c}}</textarea> <br/> <span id="location" class="alert alert-info">Location: {{Latitude__c}},{{Longitude__c}}</span> <br/> <br/> <a id="save" class="btn btn-success">Save</a> <a id="cancel" class="btn btn-danger">Cancel</a> </div>

The form contains the HTML that will be used to generate the user interface. Values wrapped in double brackets "{{" and "}}" will be populated by data passed into the Mustache templating engine. Each value inside of the brackets corresponds to an attribute of a data object passed into Mustache.js.

The HTML string for the UI is generated using the Mustache.to_html() function. You can see in the setupFormView function above that the to_html() function uses a data parameter to generate the template HTML. When creating a new Lead, an empty object is passed into this function, so the form's HTML has blank values. When editing an existing lead, this exact function gets invoked, however a populated data object is passed in. This reuses the exact same HTML template, however populates it with the data that was passed in.

When rendered within the PhoneGap application, you'll see the form displayed as shown below. The GPS location is obtained through the PhoneGap API when capturing a new Lead.

 

The New Lead form displays the GPS location from the PhoneGap API
Figure 13 : The New Lead form displays the GPS location from the PhoneGap API

 

The user can enter appropriate data, and click either "Save" or "Cancel". If the user cancels, the application will take the user back. However, if the user saves, this is where the application pushes data to Database.com.

Inside of the saveFormData() JavaScript function, the data is retrieved from the input form, and assigned to a "data" object, which will be sent to Database.com. The saveFormData() function is used for both creating a new Lead, as well as updating and existing lead. If the currentLead variable exists, then the user is currently editing an existing Lead, otherwise the user is creating a new lead. If the user is creating a new Lead, the forcetk client.create function is invoked, otherwise, the client.update function is invoked.

function saveFormData( event ) { var data = {}; data.First__c = $("#first").val(); data.Last__c = $("#last").val(); data.Telephone__c = $("#phone").val(); data.Email__c = $("#email").val(); data.Notes__c = $("#notes").val(); if ( currentLead ) { //copy it back to the object in memory currentLead.First__c = data.First__c; currentLead.Last__c = data.Last__c; currentLead.Telephone__c = data.Telephone__c; currentLead.Email__c = data.Email__c; currentLead.Notes__c = data.Notes__c; //use the original lat/lon location data.Latitude__c = currentLead.Latitude__c; data.Longitude__c = currentLead.Longitude__c; } else if ( lastCoords ) { data.Latitude__c = lastCoords.latitude; data.Longitude__c = lastCoords.longitude; } try { if ( currentLead == undefined ) { sfw.client.create("Lead__C", data, saveDataSuccess, saveDataError ); } else { sfw.client.update("Lead__C", currentLead.Id, data, saveDataSuccess, saveDataError ); } } catch(e){ console.log(e); } } function saveDataSuccess( result ) { alert("Data Saved"); navigateBackFromFormView(); } function saveDataError( request, status, error){ console.log( request.responseText ); alert( request.responseText ); }

When calling client.create(), you just need to pass the type of object, the data object, and success and error callback functions. When referencing the type of object, you may have noticed that it is "Lead__c", instead of "Lead", as you may have expected. This is because custom objects and custom data fields in Database.com must use a "__c" suffix.

When calling client.update(), you need to pass the type of object, the ID of the object being updated, the data object containing new values, and the success and error callback functions.

If there is an error when saving data, a message will be displayed to the user. If there were no errors, the user will be taken back to the previous view.

Next, let's examine the workflow for retrieving data from Database.com. From the application home screen click on the "Query My Records" button. This will invoke the setupListView() JavaScript function.

function setupListView() { resetContainer(); var html = templates.list; container.html( html ); header.html( "Leads" ); if(lastData) { renderListData(); } else { queryRecords(); } $('#cancel').tap( setupHomeView ); }

The setupListView() function will clear the container, and populate it with HTML from the templates.list template. This template doesn't actually display the data, instead it sets up the dataContainer element where list data will be displayed.

<div id="dataContainer">loading...</div> <br/><br/> <a id="cancel" class="btn btn-danger" style="width:70%">Cancel</a>

If the user is navigating back from an edit form, data that is already in memory will be rendered. However, for a new request, the queryRecords() function will be invoked.

Querying data from Database.com is very easy. When using the forcetk.js toolkit, you simply need to invoke the client.query() method, and pass in a SOQL query with success and error callback functions. SOQL is the Salesforce Object Query Language, with is very similar to SQL (Structured Query Language) used by other database offerings. SOQL enables you to create countless custom data queries from related objects, just as you may with SQL. Database.com also has an online Workbench tool that lets you test SOQL queries before putting them into your actual application.

The queryRecords() function is below, where you can see it passing in the SOQL querty to retrieve data:

function queryRecords() { var query = "SELECT Email__c,First__c,Id,Last__c,Latitude__c,Longitude__c,Notes__c,Telephone__c "+ "FROM Lead__c " + "ORDER BY Last__c, First__c" sfw.client.query( query, onQuerySuccess, onQueryError ); } function onQuerySuccess( response ) { lastData = { "records": response.records }; renderListData(); } function onQueryError( request, status, error ) { $("#dataContainer").html( "Error loading data: <br/>" + request.responseText ); }

Once data is returned from Database.com, the onQuerySuccess function will be invoked, which invokes the renderListData() function.

function renderListData() { if ( lastData ) { container.addClass("nopadding"); var html = Mustache.to_html( templates.listItem, lastData ); $("#dataContainer").html( html ); $("#dataContainer").find("li").tap( onListItemTap ); $("#cancel").tap( navigateBackFromListView ); } }

The renderListData() function uses the templates.listItem template to generate a HTML list based on the data the gets returned from the server, and then adds a "tap" event handler to all <li> elements.

Next, let's examine the contents of the templates.listItem template:

<ul> {{#records}} <li id="{{Id}}"> <strong>{{Last__c}}, {{First__c}}</strong> <div class="subtext">{{Email__c}} </div> </li> {{/records}} </ul>

This template instructs Mustache.js to loop over all "records" and will output a <li> element containing the Lead's name and email address.

Once the data is rendered, you may see the interface similar to the following screenshot. All list formatting is handled in CSS, so the visual presentation looks more like a mobile application list, instead of a bulleted HTML list.

 

CSS formatting presents list as a mobile application list
Figure 14. CSS formatting presents list as a mobile application list

When the user taps on a list item, the onListItemTap function will be invoked. This function will obtain a reference to the JavaScript object corresponding to the list item that was tapped, and then will invoke the setupFormView() function discussed earlier in this article, passing in the appropriate object.

function onListItemTap( event ) { var target = $( event.target ) while (target.get(0).nodeName.toUpperCase() != "LI") { target=target.parent(); } var id = target.attr("id"); var data = getRecordById(id); setupFormView( data ); event.preventDefault(); event.stopPropagation(); function getRecordById( id ) { if ( !lastData ) return; var records = lastData.records; for (var x=0; x<records.length; x++ ) { if (records[x].Id == id ) { return records[x]; } } }

Since it reuses the setupFormView() function, it will reuse the templates.form template, however populating it with the data retrieved from Database.com. See the screenshot below to see an example showing populated data.

 

 templates.form is reused, populated with data retrieved from Database.com
Figure 15. templates.form is reused, populated with data retrieved from Database.com

We've now covered an end-to-end solution for retrieving and persisting data in Database.com, so let's talk about deployment.

 

Deployment

One option for deployment is to export application archives from your IDE. For iOS applications you must use Xcode on OS X. For Android applications you must use Eclipse (can use Windows, Linux, or OS X), for BlackBerry applications you must BlackBerry tools, and for Windows Phone you must use Visual Studio (Windows only). Deploying to multiple platforms means having multiple development environments.

Here's where PhoneGap Build comes in to assist! PhoneGap Build enables developers to either upload their code, or point PhoneGap build at a Git or SVN repository, and PhoneGap Build will perform a cloud-based compilation, providing the user with URLs to download device-specific application binaries.

In a web browser, just navigate to http://build.phonegap.com, and log in. Once you are logged in, click on the "new app" button in the upper right hand corner. A dialog will be displayed that allows to upload your code or specify a Git or SVN repository.

 

In New app, upload your code or specify a Git or SVN repository
Figure 16. In New app, upload your code or specify a Git or SVN repository

 

Once PhoneGap Build has access to your code, it will automatically perform a cloud-based compilation, providing you with links and QR codes to download your application binaries.

 

Cloud-based compilation, with links and QR codes to download your application binaries
Figure 17. Cloud-based compilation, with links and QR codes to download your application binaries

If you use a QR code reader on a mobile device, you can download the application binary directly to that device just by snapping a picture. The QR code reader will start a download of the application binary files, which will be installed on your device.

At this point, you'll now have an application consuming data from Database.com, running on multiple devices, built on top of a single codebase. Pictured below is an image of this application running on both a Motorola Atrix (Android), and iPhone 4 (iOS).

 

The application running on both a Motorola Atrix (Android) and iPhone 4 (iOS)
Figure 18. The application running on both a Motorola Atrix (Android) and iPhone 4 (iOS)

 

The full source code for this application is available for download at https://github.com/triceam/Database.Com-PhoneGap-Sample. Feel free to use this as a starting point for your own PhoneGap and Database.com powered applications.

 

Why PhoneGap?

 

If you're still wondering whether or not PhoneGap is right for you, read on to see a few reasons you might want to use PhoneGap on your next project.

Target multiple platforms

PhoneGap enables you to leverage one codebase to target multiple mobile platforms. The Web already solved the problem of cross-platform applications with HTML, CSS, and JavaScript. PhoneGap leverages the ubiquity of HTML, CSS, and JavaScript to enable you to build mobile applications using these same technologies.

Use Existing Skills

Because PhoneGap applications are built using HTML, CSS, and JavaScript, developers don't need to learn new languages or development paradigms. Developers can quickly become productive developing mobile applications reusing skills and tools that they are already familiar with. This can save both time and money.

Reuse Existing Tools

Since PhoneGap applications leverage Web technologies, there are countless existing libraries or frameworks that you can leverage to accelerate application development. Whether it is a solution accelerator framework like jQuery or Zepto, a UI toolkit like Twitter Bootstrap, jQuery Mobile, or Sencha, or a data visualization library like Raphael.js, Highcharts, or RGraph.js, there are lots of resources both open source and commercially that you can leverage within your applications.

Extensible

PhoneGap offers some native operating system integration "out of the box". However, if you want it to do more, it can. PhoneGap's native API is built on top of an extensible foundation that enables developers to create their own custom native code that can be invoked via JavaScript applications. This enables you to make PhoneGap "do more" if you so desire. There's even a large collection of open source frameworks in existence on github at: https://github.com/phonegap/phonegap-plugins.

If you want a plugin that will enable you to build multi-screen experiences for iOS applications connected to Apple TV/Airplay, all controlled by JavaScript, then there's a plugin for that:

 

Plugin for multi-screen experiences for iOS apps connected to Apple TV/Airplay
Figure 19. Plugin for multi-screen experiences for iOS apps connected to Apple TV/Airplay

 

If you want to integrate a barcode scanner, analytics, push notifications, messaging and notifications, or advertising networks, there are plugins for those too (among many others).

If you want to use a PhoneGap web view as a component inside of a native application, well, that is possible too.

PhoneGap is a tool that enables and empowers developers to create applications that can be consumed in a variety of fashions, developed using familiar and extensible technologies.

Open Source

PhoneGap is completely free and open source. The full codebase for PhoneGap is freely accessible as a part of the Apache Cordova project. If you wish to add or change functionality, then you can do that. If you wish to build tools that build on top of PhoneGap, you can do that too. If you found a bug and want to fix it for everyone else that uses PhoneGap, then you have that ability (which is encouraged)!

 

Where to go from here

For more information on PhoneGap, go to PhoneGap Build. Learn more about the capabilities of Database.com through the Developer Center.