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 traditional 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.

Editor's Note: PhoneGap is included in the Saleforce Mobile SDK.


Phonegap-device-screen.png


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's operating system.


Phonegap-arch.png


“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, and JavaScript assets for your application to function.


Phonegap-packaging.png


For iOS devices, this outputs an IPA file, for Android, an APK file, for Windows Phone, a XAP file, etc. All of these binary formats are normal archives that you can 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 can easily 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. Learn more about the capabilities of Database.com through the Developer Center.

The Application

In this article, we 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 can 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 also allows 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 about how it was created.


Phonegap-app-flow.png


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 here.

Database

For data storage, this application uses 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 Database.com account, log in, and click Create A New Object on the System Overview screen.


Phonegap-new-object-1.png


This shows the New Custom Object dialog. Here’s where you enter the label/name for your objects. I created a Lead object to contain the leads captured by the PhoneGap application.


Phonegap-new-object-2.png


The next step is to add custom fields to the Lead object. Under the Custom Fields & Relationships section, click New to add data fields. I added fields for “First Name," “Last Name," “Latitude," “Longitude," “Notes," “Email," and “Telephone." Follow the steps in the online wizard – it will guide you through this process.


Phonegap-new-fields.png


At this point, we’ve created the data objects used to persist data captured within the application. However, there is one more step before you can use these objects within a PhoneGap application. To access the data remotely, you must create a remote access “application." The configuration of this application includes a unique key used to correctly authenticate users and identify your data objects.

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


Phonegap-remote-access-1.png


The Remote Access Edit form displays, where you specify an application name, contact email, and callback URL configuration for your application. The application name is used as descriptive text when logging into your application, and the callback URL is used to redirect the user’s browser once they have authenticated successfully.


Phonegap-remote-access-2.png


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


Phonegap-remote-access-3.png


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 communicates 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 are 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. 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 generates 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 leverages 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 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, 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 is 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 initializes, 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 needs a single parameter – a reference to a function that invokes once the user successfully logs in.

You might 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 is 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 from 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 displays.


Phonegap-login.png


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 must simply have permission to access your data objects (database) in Database.com. Once the user is successfully authenticated, the setupHomeView() function is invoked, and displays the Home screen of the application.

The setupHomeView() function resets/clears the contents of the container element, 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 sees 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.


Phonegap-welcome.png


Next, let’s examine what happens when the user clicks the Add New Record button. When the user clicks this button, the setupFormView() button is invoked, creating 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 clears the container element, and fills it with HTML from the templates.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 used to generate the user interface. Values wrapped in double brackets “{{“ and “}}” are 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 it 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.


Phonegap-new-lead.png


The user can enter appropriate data, and click either "Save" or "Cancel." If the user cancels, the application takes 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 an 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 need to pass the type of object, the data object, and success and error callback functions. When referencing the type of object, you might have noticed that it is "Lead__c," instead of “Lead," as you might have expected. This is because custom objects and custom data fields in Database.com 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 displays to the user. If there are no errors, the user is taken back to the previous view.

Next, let’s examine the workflow for retrieving data from Database.com. From the application home screen click the “Query My Records” button. This invokes 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 clears the container, and populates 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 displays.

<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 is rendered. However, for a new request, the queryRecords() function is invoked.

Querying data from Database.com is very easy. When using the forcetk.js toolkit, you 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, which 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 can 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 query 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 is 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 an HTML list based on the data 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 outputs a <li> element containing the lead’s name and email address.

Once the data is rendered, you can 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.


Phonegap-leads.png


When the user taps on a list item, the onListItemTap function is invoked. This function obtains a reference to the JavaScript object corresponding to the list item tapped, and then invokes 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 reuses the templates.form template, however populating it with the data retrieved from Database.com. See the screenshot below for an example showing populated data.


Phonegap-edit-lead.png


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, Eclipse (can use Windows, Linux, or OS X), for BlackBerry applications, BlackBerry tools, and for Windows Phone, 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 performs a cloud-based compilation, providing the user with URLs to download device-specific application binaries.

In a web browser, navigate to PhoneGap, and log in. Once you are logged in, click the new app button in the upper right hand corner. A dialog displays that allows you to upload your code or specify a Git or SVN repository.


Phonegap-build.png


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


Phonegap-build-compiled.png


If you use a QR code reader on a mobile device, you can download the application binary directly to that device by snapping a picture. The QR code reader starts a download of the application binary files, which then installs on your device.

At this point, you 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).


Phonegap-on-devices.png


The full source code for this application is available for download. 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.

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:


Phonegap-multi-screen.png


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 part of the Apache Cordova project. If you want to add or change functionality, then you can do that. If you want 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)!

Related Resources

About the Author

Andrew Trice is a Technical Evangelist with Adobe Systems. Andrew brings to the table over a decade of experience designing, implementing, and delivering rich applications for the web, desktop, and mobile devices. Andrew is an experienced architect, team leader, accomplished speaker, and published author, specializing in immersive experiences, mobile development, realtime data systems, and data visualization. You can read more on Andrew's blog and follow @andytrice on Twitter.