Technology

Implementing Push Notifications with Azure Mobile Services

By July 22, 2013 2 Comments

With the release of Social Cloud we got to use many different features of Windows Azure Mobile Services including Push Notifications. As a long time developer of mobile apps, leveraging push notifications is a great way to stay connected and engaged with your customers and Azure Mobile Services makes it really easy to implement without having the headache of deploying server infrastructure.

The Windows Azure site has some great articles on getting started with Push Notifications and setting app all the appropriate keys and certificates so make sure you read those for the specific platform you are targeting

  1. Push Notifications on Windows Store C#
  2. Push Notifications on Windows Store JavaScript
  3. Push Notifications on Windows Phone 8
  4. Push Notifications on iOS
  5. Push Notifications on Android

In this article we’ll be going through how to get the Windows Azure Mobile Services (AMS) Push Notifications on Windows Phone and iOS (using Xamarin.iOS) and using the Data Feature to send push notifications to the various platforms.

Data Feature

While AMS definitely lessens the amount of work to send a notification to multiple different platforms, there is still some work you’ll need to do, including knowing what type of notification to send to what user.  To store that info, we’ll use the AMS Data tables.  By creating a table (for us named PushChannel) we can store the info for when we want to send the notifications.

We decided to store the platform and the channel identifier.  Since we know that the channel identifier should only ever show up once in the table, we use the following code in the insert script to ensure it.

function insert(item, user, request) {
        var channelTable = tables.getTable('PushChannel');
        channelTable
            .where({ uri: item.uri })
            .read({ success: insertChannelIfNotFound });
        function insertChannelIfNotFound(existingChannels) {
            if (existingChannels.length > 0) {
                request.respond(200, existingChannels[0]);
            } else {
                request.execute();
            }
        }
}

To see more details on creating your own data tables in AMS see Getting Started with Data in Mobile Services.

Device Code

To enable push notifications to devices, we will need to add some code to the apps to receive those notifications from the server

iOS Push Notifications & Xamarin

Receiving push notifications from Azure Mobile Services to iOS is possible, but unfortunately, all code in the Push Notifications on iOS on the Windows Azure website is written using objective-C. Although you will have to go through most of that article to setup certificates, if you are using Xamarin.iOS the code is not going to work. The next few steps will go through porting this code to C# for Xamarin.iOS.

First thing we will need to do is register for remote notifications in your AppDelegate.cs file

public override bool FinishedLaunching (UIApplication application, NSDictionary options)
{
 // register for remote notifciations
 UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(UIRemoteNotificationType.Alert
   | UIRemoteNotificationType.Badge
   | UIRemoteNotificationType.Sound);
}

Next you must override a few methods in your AppDelegate.cs.  First is checking for errors in registering alerts

public override void FailedToRegisterForRemoteNotifications (UIApplication application, NSError error)
{
 new UIAlertView ("Error registering push notifications", error.LocalizedDescription, null, "OK", null).Show();
}

You must also check for any notifications received

public override void ReceivedRemoteNotification (UIApplication application, NSDictionary userInfo)
{
	// show an alert
	var body = userInfo.ValueForKey (new NSString("inAppMessage")).ToString ();
	new UIAlertView("My Alert", userInfo.ValueForKey("inAppMessage").ToString(), null, "OK", null).Show();

	// reset our badge
	UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
}

When you have successfully registered for remote notifications with Apple PNS the following method will be called in your AppDelegate.cs

public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken)
{
	// get the token we saved when we first registered
	string lastDeviceToken = NSUserDefaults.StandardUserDefaults.StringForKey("deviceToken");

	// this is why you should know some objective-C even though
	// you are using C#
	var str = (NSString)Runtime.GetNSObject (
				Messaging.intptr_objc_msgSend (deviceToken.Handle, new Selector("description").Handle));

	// we only register with Azure Mobile Services if it's a new device token
	if (!newDeviceToken.ToString().Equals(lastDeviceToken))
	{
		// get a push channel with the backend
		AcquirePushChannel (newDeviceToken, 'iOS');

		//Save the new device token for next application launch
		NSUserDefaults.StandardUserDefaults.SetString(newDeviceToken, "deviceToken");
	}
}

Not overly complex to setup your code but where you will find more challenges (or at least time required) is setting up your certificates for testing and production use. Make sure to read Push Notifications on iOS on the Windows Azure website to go through those steps.

Windows Phone Push Notifications

Since receiving push notifications on Windows Phone is different from iOS, we will need to create some new code to receive the notifications.  There are many other articles that explains the process of acquiring a Notification Channel Uri, so I’ll just add the code for completeness.  For more details on Windows Phone 8 and push notifications with Azure Mobile Services see here Push Notifications on Windows Phone 8.

var CurrentChannel = HttpNotificationChannel.Find("MyPushChannel");

if (CurrentChannel == null)
{
    CurrentChannel = new HttpNotificationChannel("MyPushChannel");
    CurrentChannel.Open();
    CurrentChannel.BindToShellToast();
}

while (CurrentChannel.ChannelUri == null)
{
    Thread.Sleep(100);
}
var uri = CurrentChannel.ChannelUri.ToString();
var platform = "WP8";

// send to the backend
AcquirePushChannel(uri, platform);

Uploading Data to Azure Mobile Services

Once we have set the uri and the platform, it’s time to add it to the Data table. Just like the rest of AMS, this is quite easy. Get the table then call InsertAsync with your model like so:

IMobileServiceTable channelTable = _mobileService.GetTable();
var channel = new PushChannel
{
    Uri = uri,
    Platform = platform
};

channelTable.InsertAsync(channel);

The beauty of using Xamarin is that we can use the above code and share that code between iOS and Windows Phone avoiding us from having us to rewrite in objective-C.  So ideally a method as follows can be created

private void AcquirePushChannel(string uri, string platform)
{
   IMobileServiceTable channelTable = _mobileService.GetTable();
   var channel = new PushChannel
   {
       Uri = uri,
       Platform = platform
   };
}

Testing Push

When you want to send out notifications to all of your users regardless of what device they are using (for example from a Custom AMS API), you now have all the information you need. First you need to cycle through all of the records in your Push Channel database and send the notification to each one. Where the code will diverge is based on the Platform category.

Here is how you deal with each of the device types

Android:

function sendAndroidMessage(serv, channel, message){
	console.log("sending android alert: " + channel.uri);
	serv.push.gcm.send(channel.uri, {text1: message}, {
                success: function(response) {
                    console.log("ADR push: ", response);
                }, error: function(error) {
                    console.log("Error sending android push: ", error);
                }
            });

}

iOS:

function sendIOSNotification(serv, channel, message) {

	try {
	serv.push.apns.send(channel.uri.replace('<','').replace('>', ''), {
            alert: "Toast: " + message,
            payload: {
                inAppMessage: "Hey, a new item arrived: '" + message + "'"
            }
        },
        {
    error : function(err) {
        // handle the error here.
        console.log('ios push returned an error', err);
    }
});

Windows Phone 8:

function sendWP8Toast(serv, channel, message ) {
	serv.push.mpns.sendToast(channel.uri, {
        text1: message
    }, {
        success: function(pushResponse) {
            console.log("WP8 push:", pushResponse);
        }
     , error: function(error) {
                if( error.shouldDeleteChannel ) {
                    var sql = "Delete from PushChannel where id = " + channel.id;
                     serv.mssql.query(sql, {
                        success: function(results) {
                        }, error: function(err) {
                            console.log('Error: ', err);
                        }
                    });
                }
                else {
                    console.log("captured error:", error);
                }
            }
    });
}

** You’ll notice that the error message for WP8 Notifications has a flag shouldDeleteChannel. If that’s the case, we delete the channel as we should 🙂

Conclusion

Push Notifications are a great way to stay connected and engaged with users of your mobile apps and Windows Azure Mobile Services makes it relatively straightforward to implement and maintain. Coupled with Xamarin, as a developer you can write code that is shared across Windows, Windows Phone, iOS and Android, which reduces your development effort and helps accelerate your time to market. If you do end up implementing push notifications, let us know, it would be great to hear your stories!

Join the discussion 2 Comments

  • Mikael says:

    Hi, Thanks for a great post on notification with Xamarin and Azure MS.
    Would you mind explaining what the “AcquirePushChannel” method looks like, and what type “newDeviceToken” should be declared as.
    Again Thanks!

    • marteaga says:

      Hi Mikael, AcquirePushChannel basically sends channel details to Azure Mobile Service and stored in a table. The newDeviceToken is essentially a string and has different meaning depending on the platform.

      Windows Phone – it’s a URI from CurrentChannel.ChannelUri that gets sent from the device to the AMS
      iOS – it’s a string token that is given after calling UIApplication.SharedApplication.RegisterForRemoteNotificationTypes which in turn calls RegisteredForRemoteNotifications method

      Hope that helps!

Leave a Reply