Add push notifications to your Xamarin.Android app

Overview

In this tutorial, you add push notifications to the Xamarin.Android quick start project so that a push notification is sent to the device every time a record is inserted.

If you do not use the downloaded quick start server project, you will need the push notification extension package. See Work with the .NET backend server SDK for Azure Mobile Apps for more information.

Prerequisites

This tutorial requires the following:

Configure a Notification Hub

The Mobile Apps feature of Azure App Service uses Azure Notification Hubs to send pushes, so you will be configuring a notification hub for your mobile app.

  1. In the Azure portal, go to App Services, and then click your app back end. Under Settings, click Push.
  2. Click Connect to add a notification hub resource to the app. You can either create a hub or connect to an existing one.

Now you have connected a notification hub to your Mobile Apps back-end project. Later you will configure this notification hub to connect to a platform notification system (PNS) to push to devices.

Enable Firebase Cloud Messaging

  1. Sign in to the Firebase console. Create a new Firebase project if you don't already have one.
  2. After your project is created, click Add Firebase to your Android app and follow the instructions provided.

  3. In the Firebase console, click the cog for your project and then click Project Settings.

  4. Click the Cloud Messaging tab in your project settings, and copy the value of the Server key and Sender ID. These values will be used later to configure the notification hub access policy, and your notification handler in the app.

Configure Azure to send push requests

  1. In the Azure portal, click Browse All > App Services, and then click your Mobile Apps back end. Under Settings, click App Service Push, and then click your notification hub name.
  2. Go to Google (GCM), enter the Server Key value that you obtained from Firebase in the previous procedure, and then click Save.

    Set the GCM API key in the portal

The Mobile Apps back end is now configured to use Firebase Cloud Messaging. This enables you to send push notifications to your app running on an Android device, by using the notification hub.

Update the server project to send push notifications

In this section, you update code in your existing Mobile Apps back-end project to send a push notification every time a new item is added. This is powered by the template feature of Azure Notification Hubs, enabling cross-platform pushes. The various clients are registered for push notifications using templates, and a single universal push can get to all client platforms.

Choose one of the following procedures that matches your back-end project type—either .NET back end or Node.js back end.

.NET back-end project

  1. In Visual Studio, right-click the server project and click Manage NuGet Packages. Search for Microsoft.Azure.NotificationHubs, and then click Install. This installs the Notification Hubs library for sending notifications from your back end.
  2. In the server project, open Controllers > TodoItemController.cs, and add the following using statements:

     using System.Collections.Generic;
     using Microsoft.Azure.NotificationHubs;
     using Microsoft.Azure.Mobile.Server.Config;
    
  3. In the PostTodoItem method, add the following code after the call to InsertAsync:

     // Get the settings for the server project.
     HttpConfiguration config = this.Configuration;
     MobileAppSettingsDictionary settings =
         this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings();
    
     // Get the Notification Hubs credentials for the Mobile App.
     string notificationHubName = settings.NotificationHubName;
     string notificationHubConnection = settings
         .Connections[MobileAppSettingsKeys.NotificationHubConnectionString].ConnectionString;
    
     // Create a new Notification Hub client.
     NotificationHubClient hub = NotificationHubClient
     .CreateClientFromConnectionString(notificationHubConnection, notificationHubName);
    
     // Sending the message so that all template registrations that contain "messageParam"
     // will receive the notifications. This includes APNS, GCM, WNS, and MPNS template registrations.
     Dictionary<string,string> templateParams = new Dictionary<string,string>();
     templateParams["messageParam"] = item.Text + " was added to the list.";
    
     try
     {
         // Send the push notification and log the results.
         var result = await hub.SendTemplateNotificationAsync(templateParams);
    
         // Write the success result to the logs.
         config.Services.GetTraceWriter().Info(result.State.ToString());
     }
     catch (System.Exception ex)
     {
         // Write the failure result to the logs.
         config.Services.GetTraceWriter()
             .Error(ex.Message, null, "Push.SendAsync Error");
     }
    

    This sends a template notification that contains the item.Text when a new item is inserted.

  4. Republish the server project.

Node.js back-end project

  1. If you haven't already done so, download the quickstart back-end project, or else use the online editor in the Azure portal.
  2. Replace the existing code in todoitem.js with the following:

     var azureMobileApps = require('azure-mobile-apps'),
     promises = require('azure-mobile-apps/src/utilities/promises'),
     logger = require('azure-mobile-apps/src/logger');
    
     var table = azureMobileApps.table();
    
     table.insert(function (context) {
     // For more information about the Notification Hubs JavaScript SDK,
     // see http://aka.ms/nodejshubs
     logger.info('Running TodoItem.insert');
    
     // Define the template payload.
     var payload = '{"messageParam": "' + context.item.text + '" }';  
    
     // Execute the insert.  The insert returns the results as a Promise,
     // Do the push as a post-execute action within the promise flow.
     return context.execute()
         .then(function (results) {
             // Only do the push if configured
             if (context.push) {
                 // Send a template notification.
                 context.push.send(null, payload, function (error) {
                     if (error) {
                         logger.error('Error while sending push notification: ', error);
                     } else {
                         logger.info('Push notification sent successfully!');
                     }
                 });
             }
             // Don't forget to return the results from the context.execute()
             return results;
         })
         .catch(function (error) {
             logger.error('Error while running context.execute: ', error);
         });
     });
    
     module.exports = table;  
    

    This sends a template notification that contains the item.text when a new item is inserted.

  3. When editing the file on your local computer, republish the server project.

Configure the client project for push notifications

  1. In the Solution view (or Solution Explorer in Visual Studio), right-click the Components folder, click Get More Components..., search for the Google Cloud Messaging Client component and add it to the project.
  2. Open the ToDoActivity.cs project file and add the following using statement to the class:

     using Gcm.Client;
    
  3. In the ToDoActivity class, add the following new code:

     // Create a new instance field for this activity.
     static ToDoActivity instance = new ToDoActivity();
    
     // Return the current activity instance.
     public static ToDoActivity CurrentActivity
     {
         get
         {
             return instance;
         }
     }
     // Return the Mobile Services client.
     public MobileServiceClient CurrentClient
     {
         get
         {
             return client;
         }
     }
    

    This enables you to access the mobile client instance from the push handler service process.

  4. Add the following code to the OnCreate method, after the MobileServiceClient is created:

    // Set the current instance of TodoActivity.
    instance = this;
    
    // Make sure the GCM client is set up correctly.
    GcmClient.CheckDevice(this);
    GcmClient.CheckManifest(this);
    
    // Register the app for push notifications.
    GcmClient.Register(this, ToDoBroadcastReceiver.senderIDs);
    

Your ToDoActivity is now prepared for adding push notifications.

Add push notifications code to your app

  1. Create a new class in the project called ToDoBroadcastReceiver.
  2. Add the following using statements to ToDoBroadcastReceiver class:

     using Gcm.Client;
     using Microsoft.WindowsAzure.MobileServices;
     using Newtonsoft.Json.Linq;
    
  3. Add the following permission requests between the using statements and the namespace declaration:

     [assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
     [assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
     [assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
    
     //GET_ACCOUNTS is only needed for android versions 4.0.3 and below
     [assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
     [assembly: UsesPermission(Name = "android.permission.INTERNET")]
     [assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
    
  4. Replace the existing ToDoBroadcastReceiver class definition with the following:

     [BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
     [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE }, 
         Categories = new string[] { "@PACKAGE_NAME@" })]
     [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK }, 
         Categories = new string[] { "@PACKAGE_NAME@" })]
     [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY }, 
     Categories = new string[] { "@PACKAGE_NAME@" })]
     public class ToDoBroadcastReceiver : GcmBroadcastReceiverBase<PushHandlerService>
     {
         // Set the Google app ID.
         public static string[] senderIDs = new string[] { "<PROJECT_NUMBER>" };
     }
    

    In the above code, you must replace <PROJECT_NUMBER> with the project number assigned by Google when you provisioned your app in the Google developer portal.

  5. In the ToDoBroadcastReceiver.cs project file, add the following code that defines the PushHandlerService class:

     // The ServiceAttribute must be applied to the class.
     [Service] 
     public class PushHandlerService : GcmServiceBase
     {
         public static string RegistrationID { get; private set; }
    
         public PushHandlerService() : base(ToDoBroadcastReceiver.senderIDs) { }
     }
    

    Note that this class derives from GcmServiceBase and that the Service attribute must be applied to this class.

    Note

    The GcmServiceBase class implements the OnRegistered(), OnUnRegistered(), OnMessage() and OnError() methods. You must override these methods in the PushHandlerService class.

  6. Add the following code to the PushHandlerService class that overrides the OnRegistered event handler.

     protected override void OnRegistered(Context context, string registrationId)
     {
         System.Diagnostics.Debug.WriteLine("The device has been registered with GCM.", "Success!");
    
         // Get the MobileServiceClient from the current activity instance.
         MobileServiceClient client = ToDoActivity.CurrentActivity.CurrentClient;
         var push = client.GetPush();
    
         // Define a message body for GCM.
         const string templateBodyGCM = "{\"data\":{\"message\":\"$(messageParam)\"}}";
    
         // Define the template registration as JSON.
         JObject templates = new JObject();
         templates["genericMessage"] = new JObject
         {
           {"body", templateBodyGCM }
         };
    
         try
         {
             // Make sure we run the registration on the same thread as the activity, 
             // to avoid threading errors.
             ToDoActivity.CurrentActivity.RunOnUiThread(
    
                 // Register the template with Notification Hubs.
                 async () => await push.RegisterAsync(registrationId, templates));
    
             System.Diagnostics.Debug.WriteLine(
                 string.Format("Push Installation Id", push.InstallationId.ToString()));
         }
         catch (Exception ex)
         {
             System.Diagnostics.Debug.WriteLine(
                 string.Format("Error with Azure push registration: {0}", ex.Message));
         }
     }
    

    This method uses the returned GCM registration ID to register with Azure for push notifications. Tags can only be added to the registration after it is created. For more information, see How to: Add tags to a device installation to enable push-to-tags.

  7. Override the OnMessage method in PushHandlerService with the following code:

    protected override void OnMessage(Context context, Intent intent)
    {          
        string message = string.Empty;
    
        // Extract the push notification message from the intent.
        if (intent.Extras.ContainsKey("message"))
        {
            message = intent.Extras.Get("message").ToString();
            var title = "New item added:";
    
            // Create a notification manager to send the notification.
            var notificationManager = 
                GetSystemService(Context.NotificationService) as NotificationManager;
    
            // Create a new intent to show the notification in the UI. 
            PendingIntent contentIntent = 
                PendingIntent.GetActivity(context, 0, 
                new Intent(this, typeof(ToDoActivity)), 0);              
    
            // Create the notification using the builder.
            var builder = new Notification.Builder(context);
            builder.SetAutoCancel(true);
            builder.SetContentTitle(title);
            builder.SetContentText(message);
            builder.SetSmallIcon(Resource.Drawable.ic_launcher);
            builder.SetContentIntent(contentIntent);
            var notification = builder.Build();
    
            // Display the notification in the Notifications Area.
            notificationManager.Notify(1, notification);
    
        }
    }
    
  8. Override the OnUnRegistered() and OnError() methods with the following code.

    protected override void OnUnRegistered(Context context, string registrationId)
    {
        throw new NotImplementedException();
    }
    
    protected override void OnError(Context context, string errorId)
    {
        System.Diagnostics.Debug.WriteLine(
            string.Format("Error occurred in the notification: {0}.", errorId));
    }
    

Test push notifications in your app

You can test the app by using a virtual device in the emulator. There are additional configuration steps required when running on an emulator.

  1. Make sure that you are deploying to or debugging on a virtual device that has Google APIs set as the target, as shown below in the Android Virtual Device (AVD) manager.

  2. Add a Google account to the Android device by clicking Apps > Settings > Add account, then follow the prompts.

  3. Run the todolist app as before and insert a new todo item. This time, a notification icon is displayed in the notification area. You can open the notification drawer to view the full text of the notification.