My real experience with building mobile applications started when Apple moved from a pure web application model for the iPhone to the App Store model, which effectively resulted in a fundamental shift in the mobile app landscape.  For one thing, we started calling them apps.  My background had always been web centric, and so the previously HTML5 based solutions made a lot of sense, and even after native development became and option and I started working with Objective-C – the speed and ease of building web-based applications was extremely appealing.

However – there were two use cases that commonly would occur when designing enterprise apps that usually meant using native code: the camera and secure offline storage.  When it comes the former, I think it is just an aftereffect of an entire populous which is used to having a camera always so close at hand.  Where previously the idea of can I associate this data point with an image might seem overly burdensome, it now belongs will within the mobile citizen’s Bill of Rights.  The latter, storing data offline, was a failure of HTML5 caused by a complete lack of a security model and competing protocols to provide a singular solution.

Enter Cordova

Naturally, these technical problems caught the attention of erstwhile hackers seeking to solve them.  Out of similar projects, I had always kept an eye on PhoneGap and frequently tested it during the early phases of development.  It’s been several cycles since then, and PhoneGap is now a very mature open source product – which is why we include it with the Salesforce Mobile SDK.

What is Cordova?  Also called PhoneGap.  Also called Callback.  Also called what happens when you let engineers re-brand things.  PhoneGap is a solution in two parts: one that is native and serves as a bridge to device functionality like the camera.  The other is a JavaScript library that knows how to talk to that bridge.  Cordova also utilizes a plugin structure, so you can extend that bridge to include new functionality (like device-based storage).

Utilizing Cordova

The first thing to realize about utlizing Cordova is that it isn’t an option with a pure HTML solution.  In other words, you can’t run a Cordova based application from Mobile Safari.  Instead you’ll use a native application that acts as a wrapper around a custom mobile browser that knows how to communicate with the Cordova libraries.  That way when JavaScript asks for the camera, the hybrid app will know how to respond.

So your first step, if you haven’t already done it, is to install the Salesforce Mobile SDK, part of the Salesforce Platform Mobile Services.  The SDK includes not only Cordova, but plugins which include additional features like handling the OAuth login flow.  Once installed, you can build both native applications (designed for Java or Objective-C) or hybrid ones.  See the Gettting Started for the Mobile SDK (iOS or Android) for more information.

Referencing Cordova

Ok – so you’ve installed the SDK and you’ve started a hybrid application project.  That gives the first half the Cordova solution: a native bridge to device functionality.  What about the second half, where we communicate to that bridge with JavaScript?  First, you need to make sure you are including the libraries.  If you are building an application where the HTML, CSS and JavaScript is stored on the device – you already have the files at hand.  For example, in XCode you might see these files:

As well as the main Cordova JavaScript itself.  These are the JavaScript files for the new functionality provided with the Salesforce Mobile SDK.  However, what if you wanted to use this functionality with a Visualforce page?  No problem – just lift the files from the project folder and include them as static resources, a la:

<apex:includeScript value="{!$Resource.Cordova}"/>
<apex:includeScript value="{!$Resource.SFHybridApp}"/>
<apex:includeScript value="{!$Resource.SFSmartstorePlugin}"/>

And in the bootconfig.js file (included in the project), update the startData variable to point to your Visualforce page.  The native application will still have the Cordova resources, and your JavaScript will still communicate with the bridge.

Accessing the Camera

Now with the two parts of Cordova able to communicate, you can start accessing native functionality.  To have the browser pull up the camera UI and hand back the resulting image, simply use:

navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 25, destinationType : Camera.DestinationType.DATA_URL });

The camera object has been added by Cordova, and this function will bring up the camera interface and then hand a successful result to the onPhotoDataSuccess method.  The options here set the quality (25%, in this case, to create a smaller footprint image) and the kind of result your code should expect.  The Data URL destination type will return a base64 URI which JavaScript can easily understand.

Using SmartStore

SmartStore is a feature of the Salesforce Mobile SDK for secure offline storage.  It is a Cordova plugin and works in a similar way.  Since it is a custom plugin, you’ll need to tell Cordova to add it to the JavaScript instance:

hybrid = cordova.require("salesforce/util/logger");
smartstore = cordova.require("salesforce/plugin/smartstore");

SmartStore uses a schema-less, NoSQL style structure called soups.  The term is a bit of jargon leftover from the original Newton project.  A soup basically has two bits to every row: An index object which defines what can be searched against, and a object storing the actual data.  So first you define your index structure:

indexes = [
		{path:"Name",type:"string"},
		{path:"Id",type:"string"}
        ];

And then you can register your soup:

navigator.smartstore.registerSoup('SoupName',indexes,successFunction,errorFunction);

Giving a callback function for success and error.  Since we don’t have SQL, you create query objects to search against records.  For instance:

var querySpec = navigator.smartstore.buildLikeQuerySpec("Name", "%Fred%", null, 20);
navigator.smartstore.querySoup('SoupName',querySpec, function(cursor) {
					records = cursor.currentPageOrderedEntries;
					navigator.smartstore.closeCursor(cursor);
					render(records);
			    },error);

Builds a query with a like operator that will search for records containing Fred anywhere in the name, then queries the soup and hands the first page off to render.  With query objects, you can set the number of records to a page (20 in our case) to structure the results into a series of arrays.

To learn more about using SmartStore, see the recently published wiki article.

Seeing it in action

I have a repo with an example Visualforce application that leverages both of these particular tricks.  In this case, we’re using Visualforce, Apex and JavaScript Remoting – but you could also be using pure HTML5, our ForceTK library (included in all of our Mobile Packs) and the REST API.  In this demo, the SmartStore is being used as a quick means to search against the current set of results:

//www.youtube.com/watch?v=T_l5b2AQyX4

tagged , , , , , Bookmark the permalink. Trackbacks are closed, but you can post a comment.
  • blogging

    Thanks,, It helped me

  • stvnhg

    Hello

    Thank you for the article! We tried your example app on iPhone and Android. We can successfully build and install your app on iOS and Android but we only get results back on iOS. On android the app just launches and the list of “merchandise” is empty. Since the app runs fine on iOS it must be something with the android project created by forcedroid right? Can you try and give me a direction to a possible solution? Thanks!