Enterprise Web Development (2014)

Part II. Enterprise Considerations

Chapter 13. Hybrid Mobile Applications

The word hybrid means something of mixed origin or composition. In the realm of mobile web applications, such a mix consists of the code written in HTML5, which accesses the APIs written in native languages. If an organization doesn’t want or can’t hire separate teams of software developers (for example, Objective-C developers for iPhone, Java for Android, C# for Windows Phone), there is a way to have one team of developers with HTML/JavaScript skills who can develop applications by having the same code deployed on various mobile devices packaged as native applications. Let’s do a quick comparison of native, web, and hybrid mobile applications.

Native Applications

We call a mobile application native if it was written not in HTML/JavaScript, but in a programming language recommended for devices of this mobile platform. The manufacturer of mobile devices releases an SDK and describes a process for creating native applications. This SDK provides an API for accessing all components (both hardware and software) of the mobile device, such as phone, contact list, camera, microphone, and others. Such SDKs include UI components that have a native look and feel, so applications developed by third parties look the same as those developed by the respective device manufacturer.

Native applications can seamlessly communicate with one another. They can use all available hardware and software components of the device to create convenient workflows to which people quickly become accustomed. For example, a person can take a picture with her mobile phone, which can figure out the current geographical location and allow her to share the photo with other people from her Contacts list. To support such functionality, a native application has to access the camera of the mobile device, use GPS to discover the device coordinates, and access the Contacts application.

If you are in the business of writing mobile flight simulators or games that heavily rely on graphics (not a Sudoku type of game), select a programming language that can use the device hardware (for example, graphic accelerators) to its fullest and works as fast as possible on this device. Faster applications use less battery power, too.

For native applications, a device manufacturer usually offers an application store, which serves as an online marketplace where people can shop for applications. Apple has the App Store for iOS and Mac OS X applications. Google has Google Play market for Android applications.BlackBerry World is a store where you can find applications for mobile devices manufactured by RIM. Microsoft has its store, too.

Other application stores are available, and having a one-stop shop is a great way to distribute consumer-oriented applications. For enterprise applications, having a public distribution channel might be less important, but enterprises still need a way to publish mobile applications for private use. Apple has the iOS Developer Enterprise Program. For Android applications, there is a Google Play Private Channel for internal distribution channels. Microsoft has its process for business applications, as well.

NOTE

The HTML5 stack is not the only way to develop hybrid applications using the same language for different mobile platforms. With Xamarin, you can develop applications in C# for iOS, Android, and Windows Phone.

Native versus Web Applications

Both web and native applications have their pros and cons. The latter are usually faster than web applications. Let’s go through some of the examples of native mobile business applications that exist today.

Bank of America, Chase, and other major banks have native mobile applications that you can use to deposit a check by taking a photo of its front and back sides and entering the amount. At the time of this writing, these applications support iPhones, Android, Windows phones, and iPads.

Native applications implementing Near-Field Communication (NFC) technology makes it possible for two NFC-enabled devices to communicate with each other at close distances by using radio frequencies. NFC can be used for payments (no need to enter passwords) and data sharing (contacts, photos, and so forth). Proliferation of NFC in banking will seriously hurt the credit card industry. A number of smartphones already support NFC technology. Add one of the existing fingerprint biometric solutions, and your mobile phone becomes your wallet.

Although native applications have full access to all APIs of the mobile device (for example, contacts, camera, and microphone), they have drawbacks, too. For instance, if you want to publish your application at Apple’s App Store, you have to submit your application in advance and wait for its approval. And later, if users run into a crucial bug in your application, even if you fixed it the same day, you can’t put a new version in production until it goes through the approval process again. Besides this inconvenience, there can be other roadblocks. For instance, back in 2011, theFinancial Times (FT) decided to stop using its native iOS application because Apple wouldn’t agree to share the data about FT subscribers with FT—the owner of this application.

Mobile web applications don’t require any third-party involvement for distribution. An enterprise can make them available at any time by simple adding a Download button on the corporate website. It’s good to have the ability to quickly publish the latest versions of web applications on your own servers without having to ask for permission. On the other hand, maintaining a presence on one of the popular app stores is a good channel for getting new customers.

The publisher of New York magazine is heavily investing in its native application for iPad, but the newer version of its web application is as engaging as its native peer. If you want your application to be discoverable and visible by search engines, develop it as a web application, not a native one.

Hybrid Applications

Hybrid applications promise you the best of both worlds. You can develop a web application in HTML/JavaScript, but access the native API of the mobile device via third-party solutions such as PhoneGap from Adobe or Titanium from Appcelerator. Let’s see what tools are available for creating hybrids.

Cordova and PhoneGap

Cordova is a library (and a build tool) that serves as a bridge between JavaScript and a native API. Cordova started from code donated by Adobe to the Apache Software Foundation. Cordova is an open source platform created for building mobile applications with HTML5, but packaged as native ones. PhoneGap is a brand owned by Adobe. Besides the Cordova library, it offers developers a remote server, on which they can package their applications for various mobile platforms. If the role of the Cordova library in the PhoneGap product is not clear to you, think of a similar situation in which the same software library is used in different products. For example, the rendering engine WebKit is used in Chrome and Safari browsers.

NOTE

Cordova can be used without PhoneGap. For example, Facebook and Salesforce use Cordova in their mobile SDK.

Figure 13-1 illustrates the interaction of PhoneGap, Cordova, and a web application.

PhoneGap, Cordova, and a web application

Figure 13-1. PhoneGap, Cordova, and a web application

PhoneGap includes APIs, a code generator, and a workflow for creating native application containers for web applications written in HTML5 (with or without JavaScript frameworks). PhoneGap also facilitates making JavaScript calls to access native APIs offered by the mobile OS.

PhoneGap Build is a cloud service to which you can upload your HTML/JavaScript/CSS code to be packaged for multiple mobile platforms. PhoneGap Build creates several native applications—one per mobile platform. Each application is a wrapper with an embedded chrome-less web browser (a.k.a. web view) that looks native to the mobile OS, and has access to various native APIs. Refer to the PhoneGap documentation to see what APIs are supported on each mobile platform. The native wrapper serves as a messaging bus between the external native API and HTML-based applications running inside the web view.

For iOS applications, the PhoneGap Build server creates an .ipa file; for deployment on Android devices, it generates an .apk file, and so on. After that, if you want to submit your application to a public or private application store, follow the procedure that exists for native applications for the selected store. The PhoneGap Build service can package your application for iOS, Android, Windows Phone, BlackBerry, and other platforms.

PhoneGap applications can run slower compared to HTML-based applications running in a mobile web browser. This is because there is yet another middleman: a web view. In Android SDK, the WebView control is used to embed an HTML5 application into a native shell, and the iOS SDK has the UIWebView control for the same purpose. Both of these controls perform slower than their respective mobile web browsers.

TIP

To compare performance of an application that runs in a mobile browser versus a WebView or UIWebView control, use Google’s V8 Benchmark Suite or SunSpider benchmark utility.

The UI components of the HTML5 framework of your choice might not look native enough. But the main selling point is that with PhoneGap (and Cordova), you can take advantage of existing HTML/JavaScript developers’ skills for all major mobile platforms, and their bridge to native APIs is easy to learn.

Titanium

Titanium offers its own set of tools and a more extensive API. It has no relation to Cordova or PhoneGap. You’d be writing code in JavaScript (no HTML or CSS) and would need to learn lots of APIs. The compiled and deployed application is JavaScript code embedded inside Java or Objective-C code, plus the JavaScript interpreter, plus the platform-specific Titanium API. An important difference between PhoneGap and Titanium is that the latter doesn’t use a web view container for rendering. The business logic written in JavaScript is executed by an embedded interpreter, and the final UI components are delivered by native application to iOS or Android components from Titanium.

Titanium UI components can be extended to use native OS interface abilities to their fullest. Some components are cross-platform; Titanium has a compatibility layer, whereas others are platform-specific. But if you want to learn platform-specific components, you might rather invest time in learning to develop the entire application in the native language and APIs. Besides, as new platforms are introduced, you’ll depend on the willingness of Titanium developers to create a new set of components in a timely fashion.

Don’t expect top performance from the old Rhino JavaScript engine, which is used by Titanium for Android and BlackBerry applications. Oracle has a new JavaScript engine called Nashorn, but it’s available only for Java 8, which doesn’t run on Android and won’t for the foreseeable future. Nashorn is as fast as Google’s V8, but Rhino is slower. Does this mean that Titanium applications on Android and BlackBerry will always run slower? This seems to be the case, unless Oracle and Google find a way to stop their quarrels about Java.

The learning curve of the Titanium API is steeper (it has over 5,000 APIs) than with PhoneGap. At the time of this writing, Titanium supports iOS, Android, and older versions of BlackBerry devices. It plans to support Windows Phone by the end of 2014.

NOTE

PhoneGap and Titanium are not the only solutions that allow building hybrid applications using HTML5. The framework Kendo UI Mobile can build hybrid applications for iOS, Android, BlackBerry, and Windows Phone 8. The Mobile Conduit API allows you to build cross-platform mobile applications with HTML5. Convertigo Mobilizer is a cross-platform enterprise mashup environment that incorporates PhoneGap and Sencha Touch for building mobile applications. IBM Worklight offers a client/server/cloud to enterprises so they can develop, test, run, and manage HTML5, hybrid, and native mobile applications.

The Bottom Line

If a particular enterprise application is intended only for internal use by people carrying a limited variety of mobile devices, and if making business users productive is your main goal, consider developing native applications, which can be fine-tuned to look and feel as best as a selected platform allows. You can start by developing and deploying your first application for the pilot mobile OS (typically for the latest iOS or Android OS) and then gradually add support for more platforms, budget permitting. If you are planning to develop a web application with a relatively simple UI and have to support a wide variety of unknown consumer devices (for example, you want to enable people to donate from any device), develop an HTML5 web application.

Consider developing a hybrid application for anything in between. In this chapter, we’ll show you how to access the camera of a mobile device by using the PhoneGap framework. Such functionality can be quite useful for our Save The Child application because kids who receive donations might want to share their success stories and publish their photos after being cured.

Still, remain open-minded about native versus hybrid discussions. Be prepared that going hybrid might not become your final choice. Picking a platform is a complex, business-specific decision that might change over the life of your application.

Introduction to the PhoneGap Workflows

In this section, you’ll go through the entire process of building a PhoneGap application. PhoneGap 3.1 offers two major workflows. Each allows you to build a mobile application, but the main difference is where you build it—either locally or remotely. Here are the options:

§  Install all required mobile SDKs and tools for the mobile platforms for which you want to develop (for example, iOS and Android), generate the initial project by using the command-line interface (CLI), write your HTML5 application code, build it locally, and then test the application by using the IDE, simulators, and physical devices.

§  Don’t install any mobile SDK and tools. Just generate the initial project by using CLI, add the application code, zip up the www folder, and upload it to Adobe PhoneGap Build server, which will build the application for all supported mobile platforms. Then, download and test the application on physical devices.

The second workflow requires running a trivial installation of PhoneGap and then just letting Adobe’s Build PhoneGap server do the build for various mobile platforms. The first workflow is more involved, and we’ll illustrate it by showing how to use the local SDKs for iOS deployment.

NOTE

For some platforms, PhoneGap supports only local builds (for example, BlackBerry 10, Windows Phone 8), whereas builds for WebOS and Symbian can be done only remotely.

In any case, you need to install the PhoneGap software according to the instructions from the command-line interface documentation. Begin by installing Node.js, which will also install its package manager npm used for installing Cordova (and the PhoneGap library). We’re developing on Mac OS X, and here’s the command that installs PhoneGap:

sudo npm install -g phonegap

This command installs the JavaScript file phonegap in /usr/local/bin and the Cordova library with supporting files in /usr/local/lib/node_modules/phonegapFigure 13-2 shows a snapshot of some of the files and directories that come with PhoneGap. We’ve highlighted the create.js script, which will be used to generate the Hello World and Save The Child projects.

PhoneGap 3.1 installed

Figure 13-2. PhoneGap 3.1 installed

In this chapter, we’ll be developing a sample application for the iOS platform to illustrate the most involved deployment-deployment cycle. It requires the Xcode IDE, which is available at Apple’s App Store at no charge. After installing Xcode, open the Preferences menu and install the Command-Line Tools (CLT) from the Downloads panel. By default, Xcode comes with the latest iOS simulator (as of this writing, this is version 6.1).

Creating One More Hello World

The time has come for a PhoneGap version of Hello World. We are going to generate the initial project by using CLI as described in the same document we used for installing PhoneGap in the preceding section. We’ll be running the phonegap script:

phonegap create HelloWorld com.example.hello "Hello World"

After generating the Hello World code with the phonegap create command (you might need to run it as a superuser with sudo), you’ll see the files and directories as depicted in Figure 13-3.

NOTE

While using the command phonegap create HelloWorld com.example.hello "Hello World", keep in mind that for iOS, you’ll need to create a certificate, which has to be valid for application packages located under com.example. For more details, see the section Testing Applications on iOS Devices.

The CLI-generated project Hello World

Figure 13-3. The CLI-generated project Hello World

The content of the generated index.html is shown in Example 13-1. It includes several meta tags instructing the browser to use the entire screen of the mobile device without allowing scaling with user’s gestures. Then it includes a couple of JavaScript files in the <script> tags.

Example 13-1. The generated file index.html

<!DOCTYPE html>

<html>

 <head>

     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

     <meta name = "format-detection" content = "telephone=no"/>

     <meta name="viewport" content="user-scalable=no, initial-scale=1,

           maximum-scale=1, minimum-scale=1, width=device-width;" />

     <link rel="stylesheet" type="text/css" href="css/index.css" />

     <title>Hello World</title>

 </head>

 <body>

     <div class="app">

         <h1>Apache Cordova</h1>

         <div id="deviceready">

             <p class="status pending blink">Connecting to Device</p>

             <p class="status complete blink hide">Device is Ready</p>

         </div>

     </div>

     <script type="text/javascript" src="phonegap.js"></script>

     <script type="text/javascript" src="js/index.js"></script>

     <script type="text/javascript">

         app.initialize();

     </script>

 </body>

</html>

Figure 13-5 is a screenshot the Hello World application running.

This HTML file includes the code to load the phonegap.js library and the initialization code from index.js.Then it calls app.initialize(). But if you look at Figure 13-3, the file phonegap.js is missing. The CLI tool will add it to the project during the next phase of code generation, when you run the command phonegap platform add to add specific mobile platforms to your project. Let’s look at the code of index.js (see Example 13-2).

Example 13-2. The file index.js

var app = {

  initialize: function() {                   1

      this.bind();

  },

  bind: function() {

    document.addEventListener('deviceready',   2

               this.deviceready, false);

  },

  deviceready: function() {

    app.report('deviceready');

  },

  report: function(id) {                        3

      console.log("report:" + id);

      document.querySelector('#' + id + ' .pending').className += ' hide';

      var completeElem = document.querySelector('#' + id + ' .complete');

      completeElem.className = completeElem.className.split('hide').join('');

  }

};

1

This function is called when all scripts are loaded in index.html.

2

The mobile OS sends the deviceready event to the PhoneGap application when it’s ready to invoke native APIs.

3

The function report() is called from the deviceready event handler. It hides the text .pending <p> and shows the text .complete <p> in index.html. Technically, split('hide') followed by join('') performs the removal of the word hide.

It wouldn’t be too difficult to prepare such simple HTML and JavaScript files manually, but we prefer using code generators. They are faster and less error prone.

NOTE

Neither Cordova nor PhoneGap restrict you from using any HTML5 frameworks of your choice.

PREREQUISITES FOR LOCAL BUILDS

If you are planning to build your application locally, install the supporting files for the required platforms. For example, you can run the following commands from the command window (switch to the HelloWorld directory) to request the builds for iOS, Android, and BlackBerry:

phonegap install ios

phonegap install android

NOTE

The first command will run fine, because we have Xcode installed. The second command will fail until you install the latest Android SDK as described in the section Installing More Local SDKs.

After running these commands, the initially empty directory platforms is filled with additional subdirectories specific to each platform. Technically, these commands generate separate Hello World projects—one per platform. Each of them will have its own www directory with index.html and phonegap.js that was missing during the initial project generation. Don’t make any modifications in these www folders, because they will be regenerated each time the install or run command is run. Make the required modification in the root www folder.

Figure 13-4 shows the content of the ios folder that was generated as a result of executing the command phonegap install ios.

CLI-generated project for the iOS platform

Figure 13-4. CLI-generated project for the iOS platform

Double-click the file Hello_World.xcodeproj, and Xcode will open it as a project. In the upper-left corner of the toolbar, click the Run button to compile the project and start it in the iOS simulator (see Figure 13-5). Note the “Device is ready” text from index.html (as per index.css, this text is blinking and is shown in uppercase).

Running Hello World in Xcode

Figure 13-5. Running Hello World in Xcode

The description of the workflow with the Build PhoneGap server follows.

Testing Applications on iOS Devices

If you want to test your application not in a simulator, but on a physical iOS device, it has to be connected to your Mac computer, enabled for deployment, and recognized by Apple. Details on provisioning your devices for development are described in the online iOS Developer Library. If you prefer shorter instructions, here’s what worked for us:

1.    Open a Keychain Access application on your Mac computer and create a certificate request by choosing Keychain Access→Certificate Assistant→Request a Certificate from Certificate Authority. This creates a file with the name extension .certSigningRequest.

2.    Log in to Member Center at developer.apple.com and create a certificate for iOS Development specifying a wildcard (an asterisk) in the Bulk name unless you want to restrict this certificate to be used only with applications that begin with a certain prefix. In this step, you’ll need to upload the .certSigningRequest file created in the previous step.

3.    After this certificate is created, download this file (its name ends with .cer), and double-click it to open it in your local keychain. Find it in the list of certificates and expand it; it should include the private key.

4.    Remain in the Member Center, and create a unique application ID.

5.    Finally, in the same Member Center, create a Provisioning Profile.

6.    In Xcode, open the menu Window→Organizer, go to the Provisioning profiles window, and refresh it. You should see the newly created provisioning profile marked with a green bullet. A physical file with the name extension .mobileprovision corresponds to this profile.

7.    Select your iOS device in the active scheme window and run your Hello World or other project on the connected device.

TIP

Read Apple’s App Distribution Guide to learn how to distribute your iOS applications.

Installing More Local SDKs

As we stated earlier, you don’t have to install SDKs locally, but if you decide to do so, consult the instructions provided by the respective mobile platform vendor. For example, BlackBerry developers can download the WebWorks SDK at developer.blackberry.com/html5/download as well as a BlackBerry 10 Simulator. If you haven’t downloaded the Ripple emulator (for instructions, see Chapter 12), you can get it there, too.

Instructions for installing the Windows Phone SDK are available at the Windows Phone Dev Center.

First, get the Android SDK. We are going to perform a simple installation by pressing the Download the SDK ADT Bundle for Mac button, which will download and install the Eclipse IDE with the ADT plug-in, Android SDK tools, Android Platform tools, and the Android platform. But if you already have the Eclipse IDE and prefer to install and configure the required tooling manually, follow the instructions published on this website in the section Setting Up an Existing IDE.

After downloading the bundle, unzip this file; it will create a folder with two subfolders: sdk and eclipse. Start Eclipse from the eclipse folder, accepting the location of the default workspace. On the top toolbar, click the plus sign (+) and open the perspective DDMS. There you can use an Android emulator while developing Android applications.

Using the Adobe PhoneGap Build Service

Instead of installing multiple SDKs for different platforms, you can use the cloud service Adobe PhoneGap Build, which already has installed and configured all supported SDKs and will do a build of your application for different platforms. For our example, we’re going to use iOS build.

Visit build.phonegap.com and sign in with your Adobe or GitHub ID. If your project resides on GitHub, copy its URL to the text field shown in Figure 13-6. The other way to do a build is to compress your project’s www directory and upload this ZIP file there.

NOTE

Starting from PhoneGap 3.0, all code modifications are done in the main www folder of your project. During local rebuilds, all the changes are automatically replicated to each installed platform’s www folder.

Submitting the application to PhoneGap Build server

Figure 13-6. Submitting the application to PhoneGap Build server

Before zipping up Hello World’s www directory, open and modify the file config.xml. The generated XML contains entries for every platform. Because we are doing a build for iOS, we remove all the lines that contain the words android or blackberry, as shown in Example 13-3.

Example 13-3. The file config.xml without Android or BlackBerry options

<?xml version='1.0' encoding='utf-8'?>

<widget id="com.example.hello" version="2.0.0"

        xmlns="http://www.w3.org/ns/widgets"

        xmlns:cdv="http://cordova.apache.org/ns/1.0">

    <name>Hello World</name>

    <description>

        A sample Apache Cordova application that responds to the deviceready event.

    </description>

    <author email="callback-dev@incubator.apache.org" href="http://cordova.io">

        Apache Cordova Team

    </author>

    <icon height="512" src="res/icon/cordova_512.png" width="512" />

    <icon cdv:platform="ios" height="144" src="res/icon/cordova_ios_144.png"

              width="144" />

    <cdv:splash cdv:platform="ios" height="748" src="res/screen/ipad_landscape.png"

                    width="1024" />

    <cdv:splash cdv:platform="ios" height="1004" src="res/screen/ipad_portrait.png"

                    width="768" />

    <cdv:splash cdv:platform="ios" height="1496" src="res/screen/ipad_retina_landscape.png"

                    width="2048" />

    <cdv:splash cdv:platform="ios" height="2008" src="res/screen/ipad_retina_portrait.png"

                    width="1536" />

    <cdv:splash cdv:platform="ios"

                    height="320" src="res/screen/iphone_landscape.png" width="480" />

    <cdv:splash cdv:platform="ios"

                    height="480" src="res/screen/iphone_portrait.png" width="320" />

    <cdv:splash cdv:platform="ios" height="640" src="res/screen/iphone_retina_landscape.png"

                    width="960" />

    <cdv:splash cdv:platform="ios" height="960" src="res/screen/iphone_retina_portrait.png"

                    width="640" />

    <feature name="http://api.phonegap.com/1.0/device" />

    <preference name="phonegap-version" value="3.1.0" />

    <access origin="*" />

</widget>

Specify the latest supported PhoneGap version in the phonegap-version attribute. The online document Using config.xml contains current information about supported versions and other essential properties. Let’s change the phonegap-version value to 3.1.0, which is the latest version supported by PhoneGap Build at the time of this writing. You’ll see other entries in config.xml of the Save The Child application.

Now select all the content inside the www folder and compress it into a ZIP file named helloworld-build.zip. Open the web browser, go to link:https://build.phonegap.com, click the Upload a ZIP File button, and select your local file helloworld-build.zip. When uploading is done, you’ll see the next screen, shown in Figure 13-7.

After helloworld-build.zip was uploaded

Figure 13-7. After helloworld-build.zip was uploaded

Click the Ready to build button to start the build for all available platforms. If you did everything right, after watching the wait cursor above each icon, all the builds will successfully complete, and you’ll see a blue line under each button. Figure 13-8 illustrates a case when the build failed for iOS and BlackBerry platforms (the first and fourth buttons are underlined in red).

TIP

You can create remote builds with the Adobe PhoneGap Build service by using the command line, too (phonegap remote build). To learn how, read the section “Build Applications Remotely” in the PhoneGap CLI Guide.

Fixing the BlackBerry version of the application is not on our agenda. Refer to the Platform Guides documentation that contains specific information on what has to be done to develop and deploy PhoneGap applications for each platform. We’ll just take care of the iOS issue.

Two builds failed

Figure 13-8. Two builds failed

After clicking the iOS button, the message “No key selected” is revealed in a drop-down box. Another error message reads, “You must provide the signing key first.” The drop-down also offers an option to add the missing key. Selecting this option reveals the panel shown in Figure 13-9.

Uploading the certificate and profile

Figure 13-9. Uploading the certificate and profile

The missing key message actually means the PhoneGap server needs the provisioning profile and the certificate discussed in the section Testing Applications on iOS Devices. The certificate has to be in the P12 format, and you can export it into the .p12 file from the Keychain Access program under Mac OS X. During the export, you’ll assign a password to the certificate that will be required by the PhoneGap Build process. After uploading the .p12 and .mobileprovision files to PhoneGap Build and unlocking the little yellow lock, rebuild the Hello World application for iOS, and it should run without any errors.

TIP

If you forgot where the .mobileprovision file is located, open Xcode and go to the menu Window→Organize, open the panel Provisioning Profiles under Library, right-click the profile record, and then select Reveal in Finder.

To complete the process, deploy the application on your mobile device, which can be done by one of the following methods:

§  Use the QR Code that was generated specifically for our application; it’s shown on the right side of Figure 13-8. Just install a QR Reader program on your device, scan this code, and the Hello World application will be installed on your device.

§  Download the application file from link:https://build.phonegap.com to your computer and then copy it onto the mobile device. For example, to get the Android version of Hello World, just click the button displaying the Android logo, and the file HelloWorld-debug.apk will download to your computer. Copy this file to your Android device and enjoy the application. For the iOS version, click the button displaying the iOS logo, which will download the file HelloWorld.ipa on your Mac computer. Double-click this file in Finder, and it will be placed into the Application section of iTunes. Synchronize the content of iTunes with your iOS device, and Hello World will be installed there.

NOTE

Using the PhoneGap Build service is free as long as you’re building public applications that have their source code hosted on a publicly accessible repository on GitHub or other hosting service. Our Hello World application is considered private because we submitted it to PhoneGap Build in a ZIP file (note the private tab in Figure 13-6). Only one private application at a time can be built for free by using PhoneGap Build. To build multiple private applications, you need to purchase an inexpensive subscription from Adobe. To replace one application with another, click its name, click the Settings button, and then click Delete this app.

Phew! This was the longest description of developing and deploying the Hello World application that we’ve ever written! We picked deployment on Apple’s devices, which is the most complicated process among all mobile platforms. And we didn’t even cover the process of submitting the application to the App Store (you’ll read more about that in the next section)! But developing and deploying an application that has to run natively on multiple platforms is expected to be more complicated than deploying an HTML5 application in a web browser.

NOTE

The Hello World application does not use any API to access the hardware of the mobile device, and it doesn’t have to. You can use PhoneGap Build simply to package any HTML5 application as a native one to be submitted to an app store.

TIP

Instead of using the JavaScript function alert(), you can display messages by using navigator.notification.alert(), and PhoneGap will display them in the native message box of the device. The Notification object also supports confirm(), beep(), and vibrate() methods.

Distributing Mobile Applications

Mobile device manufacturers set their own rules for application distribution. Apple has the strictest rules for iOS developers.

Apple runs the iOS Developer Program, and if you’re an individual who wants to distribute iOS applications via the App Store, it will cost you $99 per year. Higher education institutions that teach iOS development can enroll in this program free of charge. The iOS Developer Enterprise program costs $299 per year. To learn the differences between these programs, and visit Apple’s Developer web page.

Besides being able to deploy applications in the App Store, developers can give their beta-customers an opportunity test applications even before they are accepted in the App Store. Individual developers can share their applications with up to 100 iOS devices identified by UUID (click the serial number of your device in iTunes to see it). This is called ad hoc distribution.

For example, after the PhoneGap Build service has built the .ipa file for iOS, you can make it available for installation directly on the beta-tester’s device by using such services as diawi or TestFlight. To do so, upload the .ipa file and its provisioning profile to one of these services and you’ll get the link (a URL) to be given to your testers; the UUID of their devices must be registered with your developer’s profile. To do this, log in to your account at link:https://developer.apple.com, select the section Certificates, Identifiers & Profiles, and then go to Devices and add the UUID of the iOS device to the existing list of registered devices.

Owners of the enterprise license can distribute their applications directly from their own websites.

Android developers are not restricted in distributing their application; upload the application’s APK package to your corporate website and send the URL to anyone who’s interested. For example, the authors of this book are creating software for the insurance industry and are offering downloads of both iOS and Android versions of the application directly from their corporate website, as shown in Figure 13-10.

Distributing mobile applications at surancebay.com

Figure 13-10. Distributing mobile applications at surancebay.com

Even though simulators and emulators can be very handy, nothing is better than testing on real devices. There are several models of iPhones that vary in terms of the CPU power and screen resolution. Ensuring that an application performs well on Android devices is a lot more challenging; this market is really fragmented in both hardware and OS use. Android emulators are not as good as those for iOS. On the other hand, an iOS emulator won’t allow you to test integration with a camera. Features of real devices such as an accelerometer or gyroscope simply can’t be tested with emulators. The PhoneGap emulator is based on a Ripple add-on (see Chapter 11), with it, you can subscribe to the deviceready event and emulate responses for your custom plug-ins.

TIP

You can use TestFlight as a way to test, distribute apps, and manage provisioning profiles for iOS. HockeyApp is a platform for collecting live crash reports, getting feedback from your users, distributing your betas, recruiting new testers, and analyzing your test coverage.

If you’ve architected your hybrid application in a modularized fashion as described in Chapter 6, you’ll get an additional benefit. If the code of one of the loadable modules changes, but the main application shell remains the same, there is no need to resubmit the new version of the application to the App Store or another marketplace. This can be a serious time-saver, especially on Apple devices, because you eliminate the approval process of each new version of the application.

Save The Child with PhoneGap

To demonstrate how to turn a web application into a hybrid one, we’ll take the code of the jQuery Mobile version of the Save The Child application from Chapter 12. Initially, we’ll just turn it into a hybrid PhoneGap application as is, without adding any native API calls. After that, we’ll add to it the ability to work with a camera by using the PhoneGap API and create two builds for iOS and Android platforms. In this exercise, we’ll use PhoneGap 3.3.

NOTE

Usually, PhoneGap is mentioned in the context of building hybrid applications that need to access a native API. But you can use PhoneGap for packaging any HTML5 application as a native one, even if it doesn’t use a native API.

Using PhoneGap to Package Any HTML5 Application

Let’s go through the process of building and deploying the jQuery Mobile version of Save The Child in its existing form, without changing even one line of code. Here’s the step-by-step procedure:

1.    Generate a new PhoneGap project by using PhoneGap CLI, as we did with Hello World. This time, we won’t add any specific mobile SDKs to the project, though.

2.    Copy the existing HTML, CSS, JavaScript, and other resources from the jQuery Mobile Save The Child application into the directory www of the newly generated PhoneGap project.

3.    Create platforms where we’re planning to deploy our application:

4.  $ sudo phonegap build ios

$ sudo phonegap build android

5.    Install the following PhoneGap plug-ins that are necessary for supporting such functionality as Splashscreen, Camera, Inappbrowser, File, and File-transfer:

6.  $ sudo phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cord

7.  ova-plugin-splashscreen.git_

8.  $ sudo phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cord

9.  ova-plugin-camera.git_

10.$ sudo phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cord

11.ova-plugin-inappbrowser.git_

12.$ sudo phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cord

13.ova-plugin-file.git_

14.$ sudo phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cord

ova-plugin-file-transfer.git_

15.Test the Save The Child application on the Android, iOS, or other mobile devices.

NOTE

If you don’t have the SDKs for some of the platforms installed locally (as we did in step 2), you can compress the entire content of the www directory into a ZIP file, upload it to a PhoneGap Build server, and generate the packages for several platforms there.

Adding Camera Access to Save The Child

Charity websites help millions of people get better. When this happens, those people want to share their success stories, and maybe publish photos of themselves or their families and friends. These days, everyone uses smartphones and tablets to take pictures, and adding the ability to access the camera of a mobile device and upload photos seems like a useful feature for our Save The Child application.

We’ll add camera access to the jQuery Mobile version of our application. Example 13-4 is an extract from the file app-main.js.

Our next goal is to use PhoneGap to access the native API of the camera of the mobile device to take photos. After that, the user should be able to upload images to the server.

For starting the device’s default camera application and taking photos, PhoneGap offers the function navigator.camera.getPicture(), which takes three arguments: the name of the function handler if the photo has been successfully taken, the handler for the error, and the object with optional parameters describing the image. Details about the camera API are available in the PhoneGap documentation.

Example 13-4. Using the PhoneGap camera API

var pictureSource;

var destinationType;

var uploadedImagesPage =

                  "http://savesickchid.org/ssc-phonegap/uploaded-images.php";

var photo;

function capturePhoto() {

        navigator.camera.getPicture(

              onPhotoDataSuccess, onCapturePhotoFail,

              {

            quality : 49,

            destinationType: destinationType.FILE_URI

          });

}

function onCapturePhotoFail(message) {

        alert('Capture photo failed: ' + message);

}

function onPhotoDataSuccess(imageURL) {

        var smallImage = $('#smallImage');

        photo = imageURL;

        $('#photoUploader').css('display', 'block');

    $('#ssc-photo-app-description').css('display', 'none');

        smallImage.css('display', 'block');

        smallImage.attr("src", imageURL);

        $('#largeImage').attr("src", imageURL);

        $('#uploadPhotoBtn').removeClass('ui-disabled');

        $('#done-msg-holder').css('display', 'none');

}

Depending on the options in the third argument of getPicture(), the image will be returned as either a Base64-encoded string, or as in our case, the URI of the file where the image is saved. If the photo was taken successfully, the application will make the #photoUploader button visible.

This code sample uses quality:49 for picture quality; you can request the picture quality as a number on a scale of 1 to 100 (the larger number means better quality). Based on our experience, 49 gives a reasonable quality/file size ratio. For a current list of options, refer to the PhoneGap Camera API documentation.

TIP

For illustration purposes, the preceding code uses the JavaScript alert() function to report a failure. For a more robust solution, consider creating a custom way of reporting errors—for example, red borders, modal dialog boxes with images, or status bars.

The capturePhoto() function in Example 13-4 should be called when the user taps the button on the application’s screen. Hence, we need to register an event listener for this button. Example 13-5 is a fragment of the onDeviceReady function that registers all required event listeners.

Example 13-5. Handling events of the button that captures photos

function onDeviceReady() {

    pictureSource = navigator.camera.PictureSourceType;

    destinationType = navigator.camera.DestinationType;

        $(document).on("pageshow", "#Photo-app",

          function() {

       $('#capturePhotoBtn').on('touchstart', function(e) {

           $(e.currentTarget).addClass('button-active');

       });

       $('#capturePhotoBtn').on('touchend', function(e) {

            $(e.currentTarget).removeClass('button-active');

           capturePhoto();

       });

       $('#uploadPhotoBtn').on('touchstart', function(e) {

            $(e.currentTarget).addClass('button-active');

       });

       $('#uploadPhotoBtn').on('touchend', function(e) {

             $(e.currentTarget).removeClass('button-active');

              uploadPhoto(photo);

       });

       $('#viewGallerylBtn').on('touchend', function() {

               window.open(uploadedImagesPage, '_blank', 'location=no');

        });

          }

        );

If the user clicks the Upload Photo button, we use the FileTransfer object to send the image to the server-side script upload.php for further processing. The code to support file uploading on the client side is shown in Example 13-6.

Example 13-6. Uploading photos in JavaScript

function uploadPhoto(imageURI) {

        var uploadOptions = new FileUploadOptions();

        uploadOptions.fileKey = "file";

        uploadOptions.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);

        uploadOptions.mimeType = "image/jpeg";

        uploadOptions.chunkedMode = false;

        var fileTransfer = new FileTransfer();

        fileTransfer.upload(imageURI,

                        "http://savesickchild.org/ssc-test/upload.php",

                        onUploadSuccess, onUploadFail, uploadOptions);

        var uploadedPercentage = 0;

        var uploadedPercentageMsg = "Uploading...";

        fileTransfer.onprogress = function(progressEvent) {

                if (progressEvent.lengthComputable) {

                        uploadedPercentage = Math.floor(progressEvent.loaded /

                                      progressEvent.total * 100);

                        uploadedPercentageMsg = uploadedPercentage +

                                            "% uploaded...";

                } else {

                        uploadedPercentageMsg = "Uploading...";

                }

                $.mobile.showPageLoadingMsg("b", uploadedPercentageMsg);

        };

}

function onUploadSuccess(r) {

        $.mobile.hidePageLoadingMsg();

        $('#done-msg-holder').css('display', 'block');

        $('#uploadPhotoBtn').addClass('ui-disabled');

 }

function onUploadFail(error) {

        alert("An error has occurred: Code = " + error.code);

}

This sample code uses the PHP script located at link:http://savesickchild.org/ssc-test/upload.php. You’ll see this script in the next section. The "b" in the showPageLoadingMsg() function defines the jQuery Mobile themeFigure 13-11 is a screenshot taken on an iPhone while the Save The Child application was uploading a photo.

Uploading a photo

Figure 13-11. Uploading a photo

Providing Sever-Side Support for Photo Images

To support this application on the server side, we’ve created several PHP scripts. Of course, you can use the programming language of your choice instead of PHP.

The PHP script upload.php shown in Example 13-7 uploads the image into a folder on the server and then creates two versions of this image: a thumbnail and an optimized image. The thumbnail can be used for showing the image’s preview in a grid. The optimized image file will have reduced dimensions for showing the image in a mobile browser. This script also moves and saves the thumbnail, optimal, and original files in the corresponding folders on disk.

Example 13-7. The server-side script upload.php

<?php

function resizeAndSave ($new_width, $new_height, $input, $output, $quality) {

        // Get new dimensions

        // assign variables as if they were an array

        list($width_orig, $height_orig) = getimagesize($input);

        $ratio_orig = $width_orig/$height_orig;

        if ($new_width/$new_height > $ratio_orig) {

           $new_width = $new_height*$ratio_orig;

        } else {

           $new_height = $new_width/$ratio_orig;

        }

        //using the GD library

        $original_image = imagecreatefromjpeg($input);

        // Resampling

        $image = imagecreatetruecolor($new_width, $new_height);

        imagecopyresampled($image, $original_image, 0, 0, 0, 0, $new_width,

                       $new_height, $width_orig, $height_orig);

        // Output

        imagejpeg($image, $output, $quality);

        imagedestroy($image);

}

$timestamp = time();

$image_name = $timestamp.'.jpg';

$path_to_original = 'upload/original/'.$image_name;

if(move_uploaded_file($_FILES["file"]["tmp_name"], $path_to_original)) {

        $thumb_width = 200;

        $thumb_height = 200;

        $thumb_output = 'upload/thumbs/'.$image_name;

        $optimum_width = 800;

        $optimum_height = 800;

        $optimum_output = 'upload/optimum/'.$image_name;

        $quality = 90;

        resizeAndSave ($thumb_width, $thumb_height, $path_to_original,

                                 $thumb_output, $quality);

        resizeAndSave ($optimum_width, $optimum_height, $path_to_original,

                                   $optimum_output, $quality);

}

?>

The script uploaded-images.php (see Example 13-8) serves the web page with a list showing thumbnails of uploaded images.

Example 13-8. The server-side script uploaded-images.php

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width,initial-scale=1">

  <title>SSC. Uploaded Images</title>

  <link rel="stylesheet" href="styles.css?<?php echo(time()); ?>">

</head>

<body>

        <ul>

        <?php

            $thumbs_dir = "upload/thumbs/";

            //get all image files with a .jpg and .png extension.

            $thumbs = glob($thumbs_dir."{*.jpg,*.png}", GLOB_BRACE);

            foreach($thumbs as $thumb){

                        $filename = basename($thumb);

                        echo('<li><a href="show-img.php?p='.$filename.'">

                         <img src="'.$thumb.'"></a></li>');

            }

        ?>

        </ul>

</body>

</html>

TIP

During development, you might often be changing the CSS content. The php echo(time()); in the preceding code is just a trick to prevent the web browser from performing CSS caching during local tests. The newly generated time makes the CSS URL different on each load.

The script show-img.php in Example 13-9 shows an optimized single image in the user’s browser window.

Example 13-9. The server-side script show-img.php

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width,initial-scale=1">

  <title>The Uploaded Image</title>

  <link rel="stylesheet" href="styles.css?<?php echo(time()); ?>">

</head>

<body>

        <div id="wrapper"><?php $img=$_GET["p"];

                        echo('<img src="upload/optimum/'.$img.'">'); ?></div>

</body>

</html>

The complete source code of the PhoneGap version of the Save The Child application with camera support is available for download among the book’s code samples.

Summary

Hybrid applications make it possible for you to take an HTML5-based web application, connect it with the native API of the mobile device, and package it as a native application. The selling point of using hybrids is that you can reuse existing HTML5/JavaScript expertise. In the enterprise setup, maintaining bugs in a one-language bug database is a lot easier than if you had multiple versions of the application written in different languages. Maintaining a single set of images, videos, and CSS files is yet another advantage that lowers both time to market and cost of ownership of the application.

Thorough testing of hybrid applications is a must. With the BYOD policies, even enterprise applications must be tested on a variety of mobile devices. The development manager and application owners have to agree on the list of mobile devices on which your application will be deployed first. This has to be done in writing, in the early stages of the project, and be as detailed as possible. Statements such as “The initial version of the application will run on iOS devices” is not good enough, because the difference between an iPhone 3GS and iPhone 5 is huge. The former has 256 MB of RAM, a 600-MHz CPU, and a 480 × 320–pixel screen, whereas the latter boasts 1 GB of RAM, a three-core A6 CPU running at 1.3 GHz, and a 1135 × 640–pixel display.

Hybrid applications not only give developers and users access to the native capabilities of mobile devices, they also give you the ability to distribute your HTML5 application through multiple app stores or marketplaces offered by device manufacturers.

Enterprise managers are always concerned with the availability of paid technical support. A substantial part of this chapter was about using PhoneGap, and Adobe offers various support packages for purchase.

Make no mistake, though: if you want to create the fastest possible application that looks exactly like other applications on a selected mobile platform, develop it in the native language prescribed by the device manufacturer. Faster applications take less CPU power, which translates to a longer battery life. If you can’t hire experts in each mobile OS, going hybrid can be a practical compromise.