Today we released v1.1 of the Salesforce Mobile SDK. This latest version of the SDK has several enhancements, but the most significant change is the support for secure offline storage. You can now develop hybrid and native iOS and Android applications that (securely) store data on the device and allow the application to function even when the user is offline. This new feature of the Mobile SDK will help our customers and partners develop mobile applications that address complex use cases while still meeting the stringent security requirements that are typical of an Enterprise mobile application (e.g. what happens to my company’s sensitive data if the mobile device is lost or stolen?).
So what would it take to support offline access for our Cloud Tunes application? Funny that you should ask….
The Mobile SDK Workbook includes steps on how to download and install the Mobile SDK and so lets just focus on the setup of the new offline feature.
- SFSmartStorePlugin.js – contains the core implementation of the SDK’s offline functionality.
- SFHybridApp.js – for useful utility methods (like determining if you’re offline or not).
- You also need to include the JS file for PhoneGap since the hybrid SDK extends that library.
Initializing the offline database
SmartStore is inspired by the Apple Newton OS Soup/Store model. It also bears strong resemblance to NoSQL databases like CouchDB (e.g. the ability to store JSON values, simple key->value based storage etc.). Resisting the urge to think about the Seinfeld Soup Nazi episode, lets look at the SmartStore architecture.
You store your offline data in SmartStore in one or more ‘soups’. A soup, conceptually speaking, is a logical collection of data records—represented as JSON objects—that you want to store and query offline. In the Force.com world, a soup will typically map to a Standard or Custom Object that you wish to store offline, but that is not a hard and fast rule. You can store as many soups as you want in an application, but remember that soups are meant to be self-contained data sets; there is no direct correlation between them. In addition to storing the data itself, you can also specify indices that map to fields within the data, for greater ease and customization of data queries.
Lets take a look at the soup schema for the Cloud Tunes application to make this more tangible. You’ll find this code in the cloudtunes_smartstore.js file.
The snippet above sets up two soups – one for storing Album records, and another for storing Track records. Lines 15 and 26 show how we’ve defined indices for the respective soups. You can have as many indices in a soup as you like, but they must all be defined when you create the soup.
An index consists of a ‘path’ and a ‘type’:
- Path – Index paths map to the JSON field that should be used to index the soup data. Paths can be specified as compound hierarchies too, such as Account.Name, as long as the JSON records you save in the soup follow the same hierarchy.
- Type – is the data type, currently only string and integer types are supported.
For the Album soup, we’ve chosen to index by ‘Name’ and ‘Id’ while for the Track soup, we’ve chosen to index on ‘Name’, ‘Id’ and ‘Album__c’. With these indices defined, we can later query the offline database (i.e. soup) on these specific fields. But more on that later.
Note the calls on line 20 and 31 to the ‘registerSoup’ function of SmartStore. You need to register all the soups that your application will use to store offline data. As with other functions of the SmartStore library, ‘registerSoup’ requires success and error callback functions that get invoked by the SDK asynchronously.
Saving offline data
With the appropriate soup schema and associated indices defined, lets now look at how you can store offline data in these soups. The snippet below shows how the Cloud Tunes application stores Album records for offline use.
The first line is a JS Remoting call to the Apex Controller to retrieve Album records. We then invoke the ‘upsertSoupEntries’ method of SmartStore (line 8 ) to save those records in the Album soup. Data records stored in a soup are simply JSON objects. The beauty of using JS Remoting is that the response is already in JSON format and so you don’t have to do any further manipulation to store the data in SmartStore. As the name implies, ‘upsertSoupEntries’ will insert or update the data records (i.e. JSON objects) based on whether or not they already exist in the offline database. Each new record that is added to a soup automatically gets assigned a unique ‘_soupEntryId’ (akin to the ‘Id’ field of a Force.com record). The SDK uses this field to determine whether a record should be inserted or updated during the invocation of ‘upsertSoupEntries’.
Retrieving offline data
Next, let’s look at how you can retrieve data from the SmartStore offline database. This is typically done once you determine that the user is offline and you need the application to display previously saved offline data. The code snippet below shows how the Cloud Tunes application retrieves offline Album records.
SmartStore supports various types of queries that you can perform against a soup. Each query type has a corresponding method – e.g. ‘buildAllQuerySpec’ on line 3. The ‘All’ query type returns all records in a particular soup in random order (equivalent to a ‘select name from Account’ SOQL query). You also need to pass in the index (e.g. ‘Name’) and page size (e.g. 20) to use with the query. In addition to the ‘All’ query, SmartStore has other query types that you can use to retrieve offline data. For example, here is an ‘Exact’ query to retrieve all Tracks for a specific Album record.
In addition to ‘querySoup’, SmartStore also provides a ‘retrieveSoupEntries’ method to retrieve specific soup entries – i.e. those with a specific ‘_soupEntryId’ value.
SmartStore vs HTML5
The SmartStore functionality of the Mobile SDK provides a way for your application to store dynamic business data for offline use. What about application artifacts like the Visualforce markup, JS and CSS files, images etc.? How do you cache such static application resources on the mobile device so that they’re available in offline mode? For that you need a feature of HTML5 called Application Cache. Though the Application Cache has nothing to do with SmartStore or the Mobile SDK in general, I thought it was worth mentioning here since you’ll typically combine the SmartStore feature of the SDK with an Application Cache to implement a fully offline-enabled app. You can find more details about Application Cache and how you can use Visualforce to implement it in this blog post and the recently recorded Mobile SDK webinar.
Note also that HTML5 has other offline feature like local storage and Web SQL Database that could be used in lieu of SmartStore to persist offline data. The advantage of using the SDK’s SmartStore is that it stores all data securely on the device (using PhoneGap plugins to access native device features like SQLite) whereas HTML5 offline storage is not secure.
Implementing offline in native mobile apps
Hopefully this blog post provides you with enough information to implement offline functionality in your own mobile applications. The Mobile SDK team is constantly working on improving the SDK and adding additional functionality and so this offline feature is just a start. Its a social and mobile world out there and the Salesforce Mobile SDK is a mighty handy tool to have in such a world.