Building Mobile Apps with Appcelerator Titanium and the Salesforce REST API

This guest article by salesforce.com is a sponsored post.

Appcelerator Titanium is an increasingly popular tool for developing cross-platform mobile applications, especially for enterprise use. In this tutorial, we’re going to track and display our location history with the use of the Salesforce REST API.

REST APIs are accessible from any environment that can send an HTTP request. In many ways, it’s the most flexible way to communicate with the Salesforce1 Platform and gives you the ability to fully control your data flow.

In this tutorial, we’re going to build a Titanium app that lets you track and view your location history using Salesforce REST API.

Source code of the sample app can be found here: https://github.com/myurasov/Salesforce-REST-API-Titanium-Sample. You can import it to Titanium Studio via File > Import > Existing mobile project.

You will also need the Ti.Map module installed. Download it from https://marketplace.appcelerator.com/apps/5005 and install it using the Titanium Studio menu Help > Install Mobile Module.

Tutorial Outline

Step 1: Creating a Salesforce Connected App
Step 2: Adding a custom Object
Step 3: Understanding authentication flow with OAuth2
Step 4: Creating new “Position” object
Step 5: Logging position to the server
Step 6: Retrieving position history from the server and displaying it on a map

Creating a Salesforce Connected App

Let’s create a Connected app on Force.com:

  1. Go to https://developer.salesforce.com/signup and sign up for your Developer Edition (DE) account. For the purposes of this example, I recommend signing up for a Developer Edition even if you already have an account. This ensures you get a clean environment with the latest features enabled.
  2. Navigate to https://login.salesforce.com to log into your developer account.
  3. In the left-hand menu, choose Create > Apps and under the Connected Apps section click New to create a new Connected App.
  4. Name it “SF Sample 1,” enter your email, and check “Enable OAuth Settings.”
  5. Enter sfsampleapp://oaut-callback as your Callback URL.
  6. Add “Full access” to Selected OAuth Scopes.
  7. Save the Connected App.

Now you can see the client id of your Connected App at Create > Apps > SF Sample 1 > Manage. Edit your tiapp.xml file and replace --your-app-client-id-- with it.

Adding a custom SObject

We’re going to use a custom object for storing location data in the Salesforce cloud, so we need to create one:

  • Select Create > Objects in the side menu.
  • Click “New Custom Object” button.
  • Enter “Position” as object label, “Positions” as plural label. “Position__c” will be automatically assigned as an API name for our object. We’ll use this name for calls to the REST API.
  • Leave all other settings as default and hit Save.

Understanding authentication flow with OAuth2

Our application uses the OAuth2 protocol supported by Force.com to obtain a special string called an access token which serves as a permission to access server-side data.

The first phase of the authentication flow begins when a developer registers an application with OAuth server. We have already done this when we created a Connected App on Force.com. During this step, you also register a Callback URL which is handled by your app in the final stage of the process. After registering your app, you get the client id – the unique string which identifies your application with OAuth server.

When a user of your application tries to access a resource that is secured by auth token, your app forms an URL of a login page that contains client id and scope (list of requested permissions) as parameters and opens this URL in a web browser.

In our case, this URL looks like this:

https://login.salesforce.com/services/oauth2/authorize
?response_type=token
&display=touch
&redirect_uri=sfsampleapp://oauth-callback
&client_id=<client_id>

If the user has an account with the auth server, the user enters a login and password; otherwise, the user creates an account and proceeds. Afterwards, the user authentication server asks if the user authorizes our application for certain actions (determined by scope parameter), and if so, redirects to the Callback URL.

The callback URL contains all the information the application needs to access protected resources – auth token, API endpoint, etc:

sfsampleapp://oauth-callback
#access_token=<token>
&instance_url=https%3A%2F%2Fna15.salesforce.com
&id=https%3A%2F%2Flogin.salesforce.com%2Fid%2F00Di0000000i7UjEAI%2F005i0000002Cy97AAC
&issued_at=1398573122814&signature=NDlJ9Gnz1of90yb1%2BvIgwPtl%2FQqEU31bJZ392LZeWf3D
&scope=full
&token_type=Bearer

Meaning of some of the params:

  • access_token – temporary token that serves for authorizing access to Salesforce APIs
  • instance_url – API endpoint that should be used by our application
  • issued_at – Unix timestamp of the token creation date

You may have noticed we’re using a custom URL scheme for the callback. Our app is registered in the system as the one that opens this type of URLs, so we get a callback when the user is done with the login process on the salesforce.com website. This is achieved by adding the following lines to our app tiapp.xml file*:

<ios>

<plist>

<dict>

...

<key>CFBundleURLTypes</key>

<array>

<dict>

<key>CFBundleURLName</key>

<string>me.yurasov.sfsampleapp</string>

<key>CFBundleURLSchemes</key>

<array>

<string>Sfsampleapp</string>

</array>

</dict>

</array>

...

</dict>

</plist>

</ios>

When the auth server redirects the browser to sfsampleapp://.. URL, our app is called with an URL accessible through the Ti.App.getArguments().url variable. We read this URL and parse its parts into an object which is stored via Ti.App.Properties.setObject() call in Auth service.

Next, the user toggles the “Enable tracking” switch to the on position:

Creating a new “Position” object

When location tracking is requested, the first thing the app checks is whether we have an access token:

...
if (e.value) {

if (!Auth.get()) {
// no authorization
switchEnableTracking.value = 0;
Auth.openLogin();
} else {
createPositionObject();
}

} else {
stopGeolocation();
}
...

If there is no valid authentication data, the user is directed to the salesforce.com login page:

Otherwise, it proceeds to createPositionObject(), which calls POST HTTP method on a Positions collection to create a new resource in it. The response contains a newly created object id, which is then saved to Ti.App.positionObjectId:

// create position resource
function createPositionObject() {

var authData = Auth.get();

var xhr = Ti.Network.createHTTPClient();

xhr.onload = function (e) {
// start geolocation
Ti.App.positionObjectId = JSON.parse(e.source.responseText).id;
startGeolocation();
};

xhr.onerror = function (e) {
if (e.source.status === 401 /* unauthorized */) {
switchEnableTracking.value = 0;
Auth.openLogin();
}
};

xhr.open('POST', authData.instance_url + '/services/data/v29.0/sobjects/Position__c');
xhr.setRequestHeader('Authorization', authData.token_type + ' ' + authData.access_token);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send(JSON.stringify({'Data__c': ''}));
}

In case our token is no longer valid, we get an HTTP 401 Unauthorized response and we must open the login page one more time to get a fresh token.

Logging position to the server

We must get a location update we want to save to the server. This is achieved by calling PATCH HTTP method on our Position resource:

function onLocation(e) {

// get coordinates
var lat = Math.round(e.coords.latitude * 1000) / 1000;
var lon = Math.round(e.coords.longitude * 1000) / 1000;

positionList.unshift([lat, lon]);

// store only 25 recent positions
if (positionList.length &gt; 25) {
positionList.splice(-1);
}

// save data

var authData = Auth.get();

var xhr = Ti.Network.createHTTPClient();

xhr.open('PATCH', authData.instance_url + '/services/data/v29.0/sobjects/Position__c/' + Ti.App.positionObjectId);
xhr.setRequestHeader('Authorization', authData.token_type + ' ' + authData.access_token);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send(JSON.stringify({'Data__c': JSON.stringify(positionList)}));

}

Retrieving position history from the server and displaying it

Finally to get our data from the server, we call GET HTTP method on a Position resource:

function update() {
if (Ti.App.positionObjectId) {

var authData = Auth.get();

var xhr = Ti.Network.createHTTPClient();

xhr.onload = function (e) {
... display route on a map ...
}

// get position list
xhr.open('GET', authData.instance_url + '/services/data/v29.0/sobjects/Position__c/' + Ti.App.positionObjectId);
xhr.setRequestHeader('Authorization', authData.token_type + ' ' + authData.access_token);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send();
}
}

When the data is loaded, we display the route on a map:

Conclusion

Using the Salesforce REST APIs along with OAuth authentication is flexible and can be easily applied to pretty much any platform/environment, making salesforce.com a truly cross-platform solution.

Resources

For a comprehensive set or resources, check out: https://developer.salesforce.com/en/mobile/resources

About the Author

I am a full-stack mobile/web/connected devices developer specializing in bringing projects from the idea to full implementation. Feel free to contact me at me@yurasov.me for any comments and questions or visit my:

Thank you for reading!

*For the purpose of this tutorial, we’re supporting iOS only. For information how to handle custom URLs on Android, see https://gist.github.com/dawsontoth/840600.

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *