Build Real-time Apps with Mobile Services and Pusher
This topic shows you how can add real-time functionality to your Windows Azure Mobile Services-based app. When completed, your TodoList data is synchronized, in real-time, across all running instances of your app.
The Push Notifications to Users tutorial shows you how to use push notifications to inform users of new items in the Todo list. Push notifications are a great way to show occasional changes. However, sometimes an app needs frequent real-time notifications. Real-time notifications can be added to your mobile service using the Pusher API. In this tutorial, we use Pusher with Mobile Services to keep a Todo list synchronized when changes are made in any running instance of the app.
Pusher is a cloud-based service that, like Mobile Services, makes building real-time apps incredibly easy. You can use Pusher to quickly build live polls, chat rooms, multi-player games, collaborative apps, to broadcast live data and content, and that’s just the start! For more information, see http://pusher.com.
This tutorial walks you through these basic steps to add realtime collaboration to the Todo list application:
- Create a Pusher account
- Update your app
- Install server scripts
- Test your app
This tutorial is based on the Mobile Services quickstart. Before you start this tutorial, you must first complete Get started with Mobile Services.
Create a new Pusher account
Your first step is to create a new account to use for the tutorial. You can use the FREE Sandbox plan, it's perfect for this tutorial.
To sign up for a Pusher account
-
Log in to the Windows Azure Management Portal.
-
In the lower pane of the management portal, click New.

-
Click Store.

-
In the Choose an Add-on dialog, select Pusher and click the right arrow.
-
In the Personalize Add-on dialog select the Pusher plan you want to sign up for.
-
Enter a name to identify your Pusher service in your Windows Azure settings, or use the default value of Pusher. Names must be between 1 and 100 characters in length and contain only alphanumeric characters, dashes, dots, and underscores. The name must be unique in your list of subscribed Windows Azure Store Items.

-
Choose a value for the region; for example, West US.
-
Click the right arrow.
-
On the Review Purchase tab, review the plan and pricing information, and review the legal terms. If you agree to the terms, click the check mark. After you click the check mark, your Pusher account will begin the provisioning process.

-
After confirming your purchase you are redirected to the add-ons dashboard and you will see the message Purchasing Pusher.

Your Pusher account is provisioned immediately and you will see the message Successfully purchased Add-On Pusher. Your account has been created and you are now ready to use the Pusher service.
To modify your subscription plan or see the Pusher contact settings, click the name of your Pusher service to open the Pusher add-ons dashboard.

When using Pusher you will need to supply your Pusher app connection settings.
To find your Pusher connection settings
-
Click Connection Info.

-
In the Connection info dialog you will see your app ID, key and secret. You will use these values later in the tutorial so copy them for late use.

For more information on getting started with Pusher, see Understanding Pusher.
Update your app
Now that you have your Pusher account set up, the next step is to modify the iOS app code for the new functionality.
Install the libPusher library
The libPusher library let’s you access Pusher from iOS.
-
Download the libPusher library from here.
-
Create a group called libPusher in your project.
-
In Finder, unzip the downloaded zip file, select the libPusher-combined.a and /headers folders, and drag these items into the libPusher group in your project.
-
Check Copy items into destination group’s folder, then click Finish

This copies the libPusher files into your project.
-
On the project root in the project explorer, click Build Phases, then click Add Build Phase and Add Copy Files.
-
Drag the libPusher-combined.a file from the project explorer into the new build phase.
-
Change the Destination to Frameworks and click Copy only when installing.

-
Within the Link Binary With Libraries area, add the following libraries:
- libicucore.dylib
- CFNetwork.framework
- Security.framework
- SystemConfiguration.framework
-
Finally within Build Settings, locate the target build setting Other Linker Flags and add the -all_load flag.

This shows the -all_load flag set for the Debug build target.
The library is now installed ready for use.
Add code to the application
-
In Xcode, open the TodoService.h file and add the following method declarations:
// Allows retrieval of items by id
- (NSUInteger) getItemIndex:(NSDictionary *)item;
// To be called when items are added by other users
- (NSUInteger) itemAdded:(NSDictionary *)item;
// To be called when items are completed by other users
- (NSUInteger) itemCompleted:(NSDictionary *)item;
-
Replace the existing declarations of addItem and completeItem with the following:
- (void) addItem:(NSDictionary *) item;
- (void) completeItem: (NSDictionary *) item;
-
In TodoService.m, add the following code to implement the new methods:
// Allows retrieval of items by id
- (NSUInteger) getItemIndex:(NSDictionary *)item
{
NSInteger itemId = [[item objectForKey: @"id"] integerValue];
return [items indexOfObjectPassingTest:^BOOL(id currItem, NSUInteger idx, BOOL *stop)
{
return ([[currItem objectForKey: @"id"] integerValue] == itemId);
}];
}
// To be called when items are added by other users
-(NSUInteger) itemAdded:(NSDictionary *)item
{
NSUInteger index = [self getItemIndex:item];
// Only complete action if item not already in list
if(index == NSNotFound)
{
NSUInteger newIndex = [items count];
[(NSMutableArray *)items insertObject:item atIndex:newIndex];
return newIndex;
}
else
return -1;
}
// To be called when items are completed by other users
- (NSUInteger) itemCompleted:(NSDictionary *)item
{
NSUInteger index = [self getItemIndex:item];
// Only complete action if item exists in items list
if(index != NSNotFound)
{
NSMutableArray *mutableItems = (NSMutableArray *) items;
[mutableItems removeObjectAtIndex:index];
}
return index;
} The TodoService now allows you to find items by id and add and complete items locally without sending explicit requests to the remote service.
-
Replace the existing addItem and completeItem methods with the following code:
-(void) addItem:(NSDictionary *)item
{
// Insert the item into the TodoItem table and add to the items array on completion
[self.table insert:item completion:^(NSDictionary *result, NSError *error) {
[self logErrorIfNotNil:error];
}];
}
-(void) completeItem:(NSDictionary *)item
{
// Set the item to be complete (we need a mutable copy)
NSMutableDictionary *mutable = [item mutableCopy];
[mutable setObject:@(YES) forKey:@"complete"];
// Update the item in the TodoItem table and remove from the items array on completion
[self.table update:mutable completion:^(NSDictionary *item, NSError *error) {
[self logErrorIfNotNil:error];
}];
} Note that items are now added and completed, along with updates to the UI, when events are received from Pusher instead of when the data table is updated.
-
In the TodoListController.h file, add the following import statements:
#import "PTPusherDelegate.h"
#import "PTPusher.h"
#import "PTPusherEvent.h"
#import "PTPusherChannel.h"
-
Modify the interface declaration to add PTPusherDelegate to look like the following:
@interface TodoListController : UITableViewController<UITextFieldDelegate, PTPusherDelegate>
-
Add the following new property:
@property (nonatomic, strong) PTPusher *pusher;
-
Add the following code that declares a new method:
// Sets up the Pusher client
- (void) setupPusher;
-
In TodoListController.m, add the following line under the other @synthesise lines to implement the new property:
@synthesize pusher = _pusher;
-
Now add the following code to implement the new method:
// Sets up the Pusher client
- (void) setupPusher {
// Create a Pusher client, using your Pusher app key as the credential
// TODO: Move Pusher app key to configuration file
self.pusher = [PTPusher pusherWithKey:@"**your_app_key**" delegate:self encrypted:NO];
self.pusher.reconnectAutomatically = YES;
// Subscribe to the 'todo-updates' channel
PTPusherChannel *todoChannel = [self.pusher subscribeToChannelNamed:@"todo-updates"];
// Bind to the 'todo-added' event
[todoChannel bindToEventNamed:@"todo-added" handleWithBlock:^(PTPusherEvent *channelEvent) {
// Add item to the todo list
NSUInteger index = [self.todoService itemAdded:channelEvent.data];
// If the item was not already in the list, add the item to the UI
if(index != -1)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
[self.tableView insertRowsAtIndexPaths:@[ indexPath ]
withRowAnimation:UITableViewRowAnimationTop];
}
}];
// Bind to the 'todo-completed' event
[todoChannel bindToEventNamed:@"todo-completed" handleWithBlock:^(PTPusherEvent *channelEvent) {
// Update the item to be completed
NSUInteger index = [self.todoService itemCompleted:channelEvent.data];
// As long as the item did exit in the list, update the UI
if(index != NSNotFound)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
[self.tableView deleteRowsAtIndexPaths:@[ indexPath ]
withRowAnimation:UITableViewRowAnimationTop];
}
}];
} -
Replace the **your_app_key** placeholder with the app_key value you copied from the Connection Info dialog earlier.
-
Replace the onAdd method with the following code:
- (IBAction)onAdd:(id)sender
{
if (itemText.text.length == 0) {
return;
}
NSDictionary *item = @{ @"text" : itemText.text, @"complete" : @(NO) };
[self.todoService addItem:item];
itemText.text = @"";
} -
In the TodoListController.m file, locate the (void)viewDidLoad method and add a call to the setupPusher method so the first few lines are:
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupPusher]; -
At the end of the tableView:commitEditingStyle:forRowAtIndexPath method, replace the call to completeItem with the following code:
// Ask the todoService to set the item's complete value to YES
[self.todoService completeItem:item];
The app is now able to receive events from Pusher, and to update the local Todo list accordingly.
Install server scripts
All that remains is setting up your server scripts. We'll insert a script for when an item is inserted or updated into the TodoList table.
-
Log on to the Windows Azure Management Portal, click Mobile Services, and then click your mobile service.
-
In the Management Portal, click the Data tab and then click the TodoItem table.

-
In TodoItem, click the Script tab and select Insert.

This displays the function that is invoked when an insert occurs in the TodoItem table.
-
Replace the insert function with the following code:
var Pusher = require('pusher');
function insert(item, user, request) {
request.execute({
success: function() {
// After the record has been inserted, trigger immediately to the client
request.respond();
// Publish event for all other active clients
publishItemCreatedEvent(item);
}
});
function publishItemCreatedEvent(item) {
// Ideally these settings would be taken from config
var pusher = new Pusher({
appId: '**your_app_id**',
key: '**your_app_key**',
secret: '**your_app_secret**'
});
// Publish event on Pusher channel
pusher.trigger( 'todo-updates', 'todo-added', item );
}
} -
Replace the placeholders in the above script with the values you copied from the Connection Info dialog earlier:
-
**your_app_id** : the app_id value -
**your_app_key** : the app_key value -
**your_app_key_secret** : the app_key_secret
-
Click the Save button. You have now configured a script to publish an event to Pusher every time a new item is inserted into the TodoItem table.
-
Select Update from the Operation dropdown.
-
Replace the update function with the following code:
var Pusher = require('pusher');
function update(item, user, request) {
request.execute({
success: function() {
// After the record has been updated, trigger immediately to the client
request.respond();
// Publish event for all other active clients
publishItemUpdatedEvent(item);
}
});
function publishItemUpdatedEvent(item) {
// Ideally these settings would be taken from config
var pusher = new Pusher({
appId: '**your_app_id**',
key: '**your_app_key**',
secret: '**your_app_secret**'
});
// Publish event on Pusher channel
pusher.trigger( 'todo-updates', 'todo-completed', item );
}
} -
Repeat step 5 for this script to replace the placeholders.
-
Click the Save button. You have now configured a script to publish an event to Pusher every time a new item is updated.
Test your app
To test the app you'll need to run two instances. You can run one instance on an iOS device and another in the iOS simulator.
-
Connect your iOS device, press the Run button (or the Command+R key) to start the app on the device, then stop debugging.
You now have your app installed on your device.
-
Run the app on the iOS simulator, and at the same time start the app on your iOS device.
Now you have two instances of the app running.
-
Add a new Todo item in one of the app instances.
Verify that the added item appears in the other instance.
-
Check a Todo item to mark it complete in one app instance.
Verify that the item disappears from the other instance.
Congratulations, you have successfully configured your mobile service app to synchronise across all clients in realtime.
Next Steps
Now that you’ve seen how easy it is to use the Pusher service with Mobile Services, follow these links to learn more about Pusher.
To learn more about registering and using server scripts, see Mobile Services server script reference.