How to build a mobile app for Force.com using jQuery Mobile and push notifications

Salesforce was the first major SaaS company and has a thriving ecosystem of apps built on top of their Force.com APIs.

David Hecht of CloudAmp and I built a mobile app for Salesforce Chatter, called Sales Square. In this post, we’ll cover how we built it using Trigger.io and the Force.com APIs with mobile features such as push notifications, geolocation and camera.

The app lets your team check in with where they are and what opportunities they are working on and notifies the rest of the team. Here is a demo screencast showing the app in action:

Here’s how we built it:

Getting Started with jQuery Mobile

You can see the full code for Sales Square in Github.

I started by creating the basic structure of the app to use  jQuery Mobile which makes styling and page transitions simple – you can see that in index.html.

First, embed the style and script tags in the head:

	<head>
		<title>Sales Square</title>
		<link rel="stylesheet" href="css/jquery.mobile-1.1.0.min.css" />
		<link rel="stylesheet" href="css/style.css" />
		<script src="js/jquery-1.7.1.min.js"></script>
		<script type="text/javascript">
			$(document).bind("mobileinit", function(){
				$.mobile.defaultPageTransition = 'none';
			});
		</script>
		<script src="js/jquery.mobile-1.1.0.min.js"></script>
		<script type="text/javascript" src="js/map.js"></script>
		<script type="text/javascript" src="js/salesforce.js"></script>
		<meta name="viewport" content="width=device-width, maximum-scale=1, minimum-scale=1, user-scalable=no">
	</head>

You can see in this snippet, that we set the default page transition to ‘none’ rather than using the normal slide animation that comes out-of-the box with jQuery Mobile. That’s a personal preference, but I prefer to avoid animation so the performance appears snappy.

Second, I create the basic structure of the app with the different pages in the body. There are four pages in the app:

  • Homepage with check-in button
  • Map showing check-ins
  • Map to confirm your location while checking in
  • List of opportunities to select which you’re working on

So here’s the HTML to create those:

        <div data-role="page" id="one" data-url="one">

		<div data-role="content" class="ui-content" role="main">

			<button id="checkin">Check-in with photo</button>

		</div><!-- /content -->

	</div>

	<div data-role="page" id="two" data-url="two"></div>

	<div data-role="page" id="three" data-url="three"></div>

	<div data-role="page" id="four" data-url="four">

		<ul data-role="listview">

		</ul>
	</div>

With that created, moving from page one to two is as simple as:

location.href = "#two";

Now, SalesSquare uses a native topbar and tabbar to help with the navigation, the camera so you can take a photo of where you are during the check-in process and location look-up to center the map.

You can see snippets covering those features in main.js and map.js, and we’ve blogged in detail before about how to use those features:

So let’s jump straight in with what’s new: Salesforce integration and setting up push notifications.

Salesforce oauth and API calls

First you need to sign-up for a Salesforce developer account so that you can create your consumer key for oath authentication.

We have general documentation on oauth authentication with Trigger.io but here’s how to do it for Salesforce. You can follow along with the code in salesforce.js.

First open a modal dialog with the right authentication url, you can see this in the ‘login’ function:

forge.tabs.openWithOptions({
	url: "https://login.salesforce.com/services/oauth2/authorize?client_id=" + salesforce.consumer_key + "&display=touch&response_type=token&redirect_uri="+encodeURIComponent("https://login.salesforce.com/services/oauth2/success"),
	pattern: "https://login.salesforce.com/services/oauth2/succ*",
	title: "Salesforce Login",
	tint: [10,49,115,255],
	buttonTint: [10,49,115,255]
}, function(data) {
	state.token = decodeURIComponent(data.url.split('#access_token=')[1].split('&')[0]);
	forge.prefs.set('token', state.token);
	salesforce.getIdentity(decodeURIComponent(data.url.split('&id=')[1].split('&')[0]));
});

You can see here that we specify a redirect url and then make sure it matches the ‘pattern’ parameter that is passed to ‘forge.tabs.openWithOptions’. This is so the modal dialog automatically closes when the success redirect url is reached. And we can then access the token and other parameters that are passed back by Salesforce.

Next, using the access token we’ve just received, we retrieve the user’s identity, you can see this in the ‘getIdentity’ function:

forge.request.ajax({
	url: url,
	type: "POST",
	data: {
		"version": "latest",
		"format": "json",
		"oauth_token": state.token
	},
	headers: {
		"Authorization": "OAuth "+ state.token
	},
	success: function (data) {
		if (typeof data == "string") {
			data = JSON.parse(data);
		}
		state.identity = data;
		forge.prefs.set('identity', JSON.stringify(state.identity));
		salesforce.getOpportunities();
		subscribe(); //Subscribe for push notification for this organization
	},
	error: function(data) {
		forge.logging.log('Error getting identity');
		forge.logging.log(data);
	}
});

You need the identity object in order to be able to construct the right urls for querying the opportunities and posting to chatter, which, at this point, is simple. Check out the ‘getOpportunities’ and ‘post’ functions in salesforce.js and you’re there:

forge.request.ajax({
	url : state.identity.urls.query.replace("{version}", "24.0") + "?q=" + encodeURI("SELECT Name FROM Opportunity where StageName='Prospecting' or StageName='Qualification'"),
	headers : {
		'Authorization' : 'OAuth ' + state.token
	},

...

forge.request.ajax({
	url : state.identity.urls.feeds.replace("{version}", "25.0") + "/news/"+state.identity.user_id+"/feed-items",
	type: "POST",
	headers : {
		'Authorization' : 'OAuth ' + state.token
	},
	data: {
		"type": "Text",
		"text": msg
	},
...

Finally, we add some bootstrap code to check if we already have the identity and token or if we need to kick off the oauth flow:

forge.prefs.get('token', function(token) {
	forge.prefs.get('identity', function(identity) {
		if (token && identity) {
			state.token = token;
			state.identity = JSON.parse(identity);
			salesforce.getOpportunities();
		} else {
			salesforce.login();
		}
	});
});

Setting up push notifications with Parse

Ok, the final tricky part of the app is setting up push notifications so that when one user checks in, others in the organization are notified.

There is some setup to be done here – Trigger.io integrates with parse.com to provide push notifications, so you’ll need to create an account there to get the necessary tokens, and then add lines like the following in your config.json for Trigger.io:

"partners": {
    "parse": {
        "applicationId": "YourApplicationKeyZdAtirdSn02Qy6NofiU2Hf",
        "clientKey": "YourClientKeyZdAtirdSn02QQy6NofiU2Hfy6No"
    }
}

Next we’ll set up code to listen and respond to push notifications, you can see this in the ‘subscribe’ function in main.js:

function subscribe() {
	forge.partners.parse.push.subscribe('C'+state.identity.organization_id, function() {
		forge.logging.log('Successfully subscribed for push notifications');
	}, function(err) {
		forge.logging.error("Couldn't subscribe for push notifications: "+JSON.stringify(err));
	});
}

forge.event.messagePushed.addListener(function (msg) {
    forge.logging.log("Received push message:");
	forge.logging.log(msg);
	map.addCheckin(msg.opp, msg.lat, msg.lng, msg.name);
	subscribe();
});

You can see there that we subscribe to a channel named with the organization id, so we only see notifications for our own team members.

Finally we can use Parse’s REST API to trigger the push notification at the end of the check-in process:

forge.request.ajax({
	url: “https://api.parse.com/1/push”,
	type: “POST”,
	headers: {
		“X-Parse-Application-Id”: “YOUR_APP_ID”,
		“X-Parse-REST-API-Key”: “YOUR_REST_API_KEY”
	},
	contentType: “application/json”,
	dataType: ‘json’,
	data: JSON.stringify({
		channel: ‘C’+state.identity.organization_id,
		data: {
			alert: msg,
			badge: 1,
			opp: opp,
			lat: state.position.coords.latitude,
			lng: state.position.coords.longitude,
			name: state.identity.display_name
		}
	}),
	success: function() {
		forge.logging.log(‘Successfully created notification!’);
	},
	error: function(err) {
		forge.logging.log(‘Error creating notification:’);
		forge.logging.log(err);
	}
});

By passing an ‘alert’ and ‘badge’ parameter in the data we trigger a message to be shown to the user receiving the push and set a number against the icon of the Sales Square app.

That’s it

That’s the code, and you can now build it to try out in the iOS emulator using the instructions in GitHub.

Testing the push notifications on an iOS device and packaging the app up for distribution requires that you have the necessary certificates and keys setup. But once you’ve done that, you have a rich, powerful mobile app built for Salesforce!

We hope this has inspired you to build Force.com mobile apps using Trigger.io. Sign-up now to get started.

Any problems at any point? Ask the community on StackOverflow or contact support@trigger.io.