Xamarin Push Notifications Using Azure Notifications Hub

How to use Azure Notifications Hub with Xamarin to deliver push notifications to Android, iOS, Windows Phone and Windows Store

One of the biggest problems when working with multiple mobile platforms is push notifications. You need to understand how to interact with every one of the backends from Apple, Google and Microsoft to be able to send the notifications to the devices. Azure has an awesome service called Notifications Hub, part of Service Bus, that help you to simplify this task.

Configuring a new Notifications Hub

To start, you will need to configure a new notification hub for your application. To make this you need to go to the Azure Management Portal and set up a new notifications hub, inside the Service Bus as in the following:
You  will need to indicate a service name, the execution region for the service and a namespace name. After completing all data and tap on the "CREATE A NEW NOTIFICATION HUB" button in the bottom-right corner, you can access it from the Service bus menu in the left side of the screen.

For the first time, you will need to configure each mobile platform store credentials, so your new Notification Hub could communicate with each of them:
  • Apple Store: You need to generate a digital certificate with your Apple developer account.
  • Windows Phone (MPNS): You need to generate a digital certificate.
  • Windows y Windows Phone (WNS): You need to enter the application Live Services SID and secret key.
  • Google Play: You need to get a Google Cloud Messaging (GCM) key. 
There are two possible configurations for Windows Phone. The first one, the Microsoft Push Notifications Service (MPNS) is for applications compiled for Windows Phone 7.X or Windows Phone 8.0. The second, Windows Notifications Service (WNS) was introduced for Windows Store applications and is used also in Windows Phone 8.1 applications.
 
In this article you can see how to get and configure the Notification Hub with Windows (WNS) and Android (GCM). For the Apple Store, the needs for a pay developer account blocks me at this moment to create the certificate.

WNS

To get the secret key and SID of your application Live Services, you need to first associate your application with the store from Visual Studio and reserve a name for it. This doesn't mean that the app needs to be published. After this, you can go to the Windows Store to reserve an application and open the Services step:

There you will find a link to the Live Services site:

In the live Services site for our application, we need to take note of the package SID and client secret key:

This data is what you need to add to the Notifications Hub WNS configuration section:

And you are ready! Now all you need to do is configure the work with the Windows Notifications Service and send notifications to your Windows Store and Windows Phone app.

Google Play

Google asks us to also make some configuration in the Google developer console. Note here you don't need to have a paid account actually to do that.
The first step is to go to the Google developer console web site: http://console.developers.google.com and create a new project for your application. In this sample, I create a new project called NSHubSample and assigned an id nshubsample-xamarin to it.
Inside the new project, you need to go to the APIs section and activate Google Cloud Messaging for the Android API. You can then go to the credentials section and create a new server key (public key) and take note of it:

Now you can return to the Notifications Hub configuration and enter this API KEY in the Google cloud messaging key configuration:

And now you have everything configured to send notifications to Android, Windows and Windows Phone applications. As a last step in Azure Management Portal, you will need the connection strings to communicate between your backend and the Notifications Hub and to register the apps at runtime with the Notifications Hub. You can find the connection strings in the main page of the Notification Hub, in the Dashboard, clicking on "View Connection String" link:

After clicking it, a new popup is shown with the two connection strings:
 

Take note of both since you will need them in a short time. Now it is time to start working on the client side of the things. With Xamarin, you will create a new Android, Windows and Windows Phone application and configure them to register with their cloud service and send the registration information to the Notifications Hub when needed. Also you will prepare them to receive notifications.

Getting the apps notification channels

With Xamarin you are able to share lots of code, the one needed for registering your device/app with every cloud provider is unique for each platform.

Windows XAML

To start, you will need to install the "Windows Azure Service Bus Managed for Windows Store and Windows Phone" NuGet package in your project. This package will make it easier to send to your Notifications Hub to the app notification channels.
To obtain these channels, you can use the PushNotificationChannelManager class, from the Windows.Networking.PushNotifications namespace. Inside that class, you will find a method called CreatePushNotificationChannelForApplicationAsync. When you get your notification channel, you need to send it to your Notifications Hub, creating a new instance of the NotificationHub class and sending as parameters:
  • The name of your notification hub, in this sample: nhsampledemo.
  • One of the connection strings you get before, the one called: DefaultListenSharedAccessSignature
Finally, you invoke the RegisterNativeAsynd method, passing the URI obtained as your notification channel:
  1. private async void InitNotificationsAsync()  
  2. {  
  3.     var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();  
  4.   
  5.     var hub = new NotificationHub("nhsampledemo""<Endpoint listen>");  
  6.     var result = await hub.RegisterNativeAsync(channel.Uri);  
  7. }  

And that's all you need in Windows XAML to obtain and configure the notifications. 

Android 

With Android, you will need to first install a new component in your Xamarin project, called "Google Cloud Messaging Client". To make this, right-click the Components folder in your Xamarin Android project and select the "Get more components" option. A new window popup lists the available components. Search for "Google Cloud Messaging Client" and click over it, in the details page, click on the "Add to app" Green button:

To register your application, you will also need the Google developer console project ID you created before. You can find it in the main page of the project:

Now you can start writing the code needed to register your app with Google Cloud Messaging. For example, in the OnCreate method of your first view:
  1. private void RegisterWithGCM()  
  2. {  
  3.     GcmClient.CheckDevice(this);  
  4.     GcmClient.CheckManifest(this);  
  5.     GcmClient.Register(this"<PROJECT ID>");  
  6. }  
The CheckDevice method ensures the device the app is running on support Google Play services, needed for notifications. CheckManifest method ensures your manifest is correctly configured, if needed and the Register method registers this application with the Project ID you get from Google developer console previously.
Now you have your Android app registered, but for being able to receive notifications you need to create a background service able to process them when they arrive to the device. To make this you will need the following two classes:
  • MyBroadcastReceiver, registered as the receiver of Google Cloud Messaging notifications.
  • GcmService, the actual implementation of the code needed to receive and process notifications.
First, you need to add some permissions attributes to the namespace of the classes:
  1. [assembly: Permission(Name = "notificationsHub.Android.permission.C2D_MESSAGE")]  
  2. [assembly: UsesPermission(Name = "notificationsHub.Android.permission.C2D_MESSAGE")]  
  3. [assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]  
  4.   
  5. [assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]  
  6. [assembly: UsesPermission(Name = "android.permission.INTERNET")]  
  7. [assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]  
  8.   
  9. namespace NotificationsHub.Android  
The class MyBroadcastReceiver also needs some more attributes to be properly identified. MyBroadcastReceiver will inherit from GcmBroadcastReceiverBase<T> being T = your own GcmService class:
  1. [BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]  
  2. [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE }, Categories = new string[] { "@PACKAGE_NAME@" })]  
  3. [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK }, Categories = new string[] { "@PACKAGE_NAME@" })]  
  4. [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY }, Categories = new string[] { "@PACKAGE_NAME@" })]  
  5. public class MyBroadcastReceiver : GcmBroadcastReceiverBase<GcmService>  
  6. {  
  7.     public static string[] SENDER_IDS = new string[] { "<PROJECT ID>" };  
  8.   
  9.     public const string TAG = "MyBroadcastReceiver-GCM";  
  10. }  
The GcmService class needs to have the service attribute and inherit from the GcmServiceBase class. Before beginning to type in the code, you will need to add a new NuGet package to your project, called "Xamarin.NotificationHub":
  1. [Service] //Must use the service tag  
  2. public class GcmService : GcmServiceBase  
  3. {  
  4.     public static string RegistrationID { getprivate set; }  
  5.     private NotificationHub Hub { getset; }  
  6.   
  7.     public GcmService() : base("<PROJECT ID>")  
  8.     {  
  9.         Log.Info(MyBroadcastReceiver.TAG, "GcmService() constructor");  
  10.     }  
  11.   
  12.     protected override async void OnRegistered(Context context, string registrationId)  
  13.     {  
  14.         Log.Verbose(MyBroadcastReceiver.TAG, "GCM Registered: " + registrationId);  
  15.         RegistrationID = registrationId;  
  16.   
  17.         createNotification("GcmService-GCM Registered...""The device has been Registered, Tap to View!");  
  18.   
  19.         Hub = new NotificationHub("nhsampledemo""<listen endpoint>");  
  20.         try  
  21.         {  
  22.             await Hub.UnregisterAllAsync(registrationId);  
  23.         }  
  24.         catch (Exception ex)  
  25.         {  
  26.             Debug.WriteLine(ex.Message);  
  27.             Debugger.Break();  
  28.         }  
  29.   
  30.         try  
  31.         {  
  32.             List<string> TAGS = new List<string>()  
  33.             {  
  34.             };  
  35.             var hubRegistration = await Hub.RegisterNativeAsync(registrationId, TAGS);  
  36.         }  
  37.         catch (Exception ex)  
  38.         {  
  39.             Debug.WriteLine(ex.Message);  
  40.             Debugger.Break();  
  41.         }  
  42.     }  
  43.   
  44.     protected override void OnMessage(Context context, Intent intent)  
  45.     {  
  46.         Log.Info(MyBroadcastReceiver.TAG, "GCM Message Received!");  
  47.   
  48.         var msg = new StringBuilder();  
  49.   
  50.         if (intent != null && intent.Extras != null)  
  51.         {  
  52.             foreach (var key in intent.Extras.KeySet())  
  53.                 msg.AppendLine(key + "=" + intent.Extras.Get(key).ToString());  
  54.         }  
  55.   
  56.         string messageText = intent.Extras.GetString("msg");  
  57.         if (!string.IsNullOrEmpty(messageText))  
  58.         {  
  59.             createNotification("New hub message!", messageText);  
  60.             return;  
  61.         }  
  62.   
  63.         createNotification("Unknown message details", msg.ToString());  
  64.     }  
  65.   
  66.     void createNotification(string title, string desc)  
  67.     {  
  68.         var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;  
  69.         var uiIntent = new Intent(thistypeof(FirstView));  
  70.         var notification = new Notification(Android.Resource.Drawable.Icon, title);  
  71.         notification.Flags = NotificationFlags.AutoCancel;  
  72.         notification.SetLatestEventInfo(this, title, desc, PendingIntent.GetActivity(this, 0, uiIntent, 0));  
  73.   
  74.         notificationManager.Notify(1, notification);  
  75.     }  
  76.   
  77.     protected override void OnError(Context context, string errorId)  
  78.     {  
  79.         //Manage errors  
  80.     }  
  81.   
  82.     protected override void OnUnRegistered(Context context, string registrationId)  
  83.     {  
  84.         //Manage unregistering services.  
  85.     }  
  86. }  
You can see four important methods in this class: OnRegistered, OnMessage, OnError and OnUnRegistered:
  • OnRegistered is executed when you register the application with the GcmClient class Register method.
  • OnMessage is executed when a new notification is received. Here the code processes the received message and shows it as a toast notification.
  • OnError, launches if an error is encountered.
  • OnUnRegistered, executes when this instance is unregistered.

iOS

In iOS you will work in the AppDelegate class. In the first place, you need to add a new component to your iOS project, in the same way you did before with Google Cloud Messaging Client for Android. This time you also need to find the Azure Mobile Services component. 

Also, we need to add a reference to the WindowsAzure.Messaging library for iOS. At this time there isn't a NuGet package available for this, but the  Android NuGet Package of Xamarin.NotificationHub is included in the monotouch folder, so you can pick it right from there. The complete name of the library is ByteSmith.WindowsAzure.Messaging.iOS.dll.

Now you can start adding code to the AppDelegate class in your iOS project. First, add a call to RegisterForRemoteNotificationTypes to the FinishedLaunching method:
  1. UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);  
Then call the method RegisteredForRemoteNotifications is called, so you need to override it:
  1. public override async void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)  
  2. {  
  3.     Hub = new NotificationHub(ConnectionString, NotificationHubPath);  
  4.     await Hub.UnregisterAllAsync(deviceToken.ToString());  
  5.     await Hub.RegisterNativeAsync(deviceToken.ToString());  
  6. }  
When a new notification is received, the method ReceivedRemoteNotification is called with the needed info so you can process the notification:
  1. public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)  
  2. {  
  3.     ProcessNotification(userInfo, false);  
  4. }  
  5.   
  6. void ProcessNotification(NSDictionary options, bool fromFinishedLaunching)  
  7. {  
  8.     // Check to see if the dictionary has the aps key.  This is the notification payload you would have sent  
  9.     if (options != null && options.ContainsKey(new NSString("aps")))  
  10.     {  
  11.         //Get the aps dictionary  
  12.         NSDictionary aps = options.ObjectForKey(new NSString("aps")) as NSDictionary;  
  13.   
  14.         string alert = string.Empty;  
  15.   
  16.         if (aps.ContainsKey(new NSString("alert")))  
  17.             alert = (aps[new NSString("alert")] as NSString).ToString();  
  18.   
  19.         //If this came from the ReceivedRemoteNotification while the app was running,  
  20.         // we of course need to manually process things like the sound, badge and alert.  
  21.         if (!fromFinishedLaunching)  
  22.         {  
  23.             //Manually show an alert  
  24.             if (!string.IsNullOrEmpty(alert))  
  25.             {  
  26.                 UIAlertView avAlert = new UIAlertView("Notification", alert, null"OK"null);  
  27.                 avAlert.Show();  
  28.             }  
  29.         }  
  30.     }  
  31. }  
And that is all you need to do with the client apps. Now let's move to the server side.

Server

In this sample source code, you will find a little WPF application acting as the server. This WPF app only has three buttons, to launch a notification to every platform registered. To make this, you need to add two NuGet packages to the project:
  • Microsoft.WindowsAzure.ConfigurationManager
  • WindowsAzure.ServiceBus 
Installing WindowsAzure.ServiceBus, installs automatically the other one as part of the dependencies. After the installation, you can start writing the "backend" code. For example, this code launches a notification for WNS:
  1. private async void Send_Windows(object sender, RoutedEventArgs e)  
  2. {  
  3.     NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<FULLSHAREDACCESS ENDPOINT>""nhsampledemo");  
  4.     var toast = @"<toast><visual><binding template=""ToastText01""><text id=""1"">Hello from a .NET App!</text></binding></visual></toast>";  
  5.     await hub.SendWindowsNativeNotificationAsync(toast);  
  6. }  
This one launches a notification for Android using Google Cloud Messaging:
  1. private async void Send_Android(object sender, RoutedEventArgs e)  
  2. {  
  3.     NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<FULLSHAREDACCESS ENDPOINT>""nhsampledemo");  
  4.     var message = "{ \"data\" : {\"msg\":\"Hello from Azure!\"}}";  
  5.     var result = await hub.SendGcmNativeNotificationAsync(message);  
  6. }  
And finally this is the iOS one: 
  1. private async void Send_iOS(object sender, RoutedEventArgs e)  
  2. {  
  3.     NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<FULL ENDPOINT>""nhsampledemo");  
  4.     var alert = "{\"aps\":{\"alert\":\"Hello from .NET!\"}}";  
  5.     await hub.SendAppleNativeNotificationAsync(alert);  
  6. }  
In all three cases, you need to create a new NotificationHubClient, using the name of the notification hub (nhsampledemo) and the Full access connection string you get from the Notification Hub dashboard before. Then you create the notification payload and use a method specific for each platform to send the notification to the Notifications Hub, who sends it to the needed platform.
To learn more details about how to write various notifications for each platform, you can have a look here:
And that's all! Now you have a Xamarin solution with notifications and understand how to create and configure an Azure Notifications Hub to use it with your cross platform solutions.
All the code for this example is available publicly in GitHub, feel free to use it any way you need.