The Xamarin team have provided a very helpful tutorial to get started with setting up Android notifications – I suggest using this to get the basic implementation working, and ensure you’re using the GcmRegistrationIntentService version, and avoid using the depreciated GCM Client.
To get a complete end to end solution up and running there is a fair bit of additional information required. Here’s a guide for using Microsoft Azure Notification Hub.
Set up Google Cloud Messaging service
Log into the Google Developer Console (https://console.developers.google.com/), and if you haven’t done so already create a project for your application.
Once created make a note of the Project ID as this will be used in your application code. When the application starts it will send the Project ID to Google to exchange for a device token. This unique token is what will be used to target each device with a notification. Be sure to check for a new token each time the application starts as it is subject to change.
Next step is to enable the Google “Cloud Messaging for Android” and create an API key:
Click credentials and create a new “Server Key” and make a note of it for later. We’ll need it for when we set up the Azure Notification Hub, and also to test sending a notification. Whist here you may want to think about how you’ll set up your dev/test/prod implementations as it’s a good idea to keep these separate.
* the key used here is for dev purposes only!
Set up the Azure notification hub
Next step is to set up the Microsoft Azure Notification Hub. Log into the portal and create a new App Service > Service Bus > Notification Hub. As soon as the service is running you can configure the Google Cloud Messaging settings by entering the API key created in the previous step into the GCM API Key field.
Set up the Android code
Before you begin, make sure you add the following to your packages.config file:
[sourcecode language=”xml”]
<package id="Xamarin.GooglePlayServices.Base" version="25.0.0.0" targetFramework="MonoAndroid50" />
<package id="Xamarin.GooglePlayServices.Gcm" version="25.0.0.0" targetFramework="MonoAndroid50" />
[/sourcecode]
For my implementation the client wanted to pop up a message when the customer is using the application as well as adding a message to the notification status bar. At the point of receiving the message I create a pending intent to display a message when the customer opens the app (by clicking the status bar message), and display a message if the application is open when the message is received.
[sourcecode language=”csharp”]
public override void OnMessageReceived (string from, Bundle data) {
Log.Info(TAG, "GCM message received");
if (from == Constants.SenderId) // make sure we sent the message
{
try
{
var messageId = data.GetString ("account");
// message ID
var message = data.GetString ("msg");
// message body
if (CurrentApplicationState.appIsInForeground)
GcmMessaging.DisplayNotificationInApp();
// create a pending intent to display to the customer at a later date
CreateSystemNotification (message, messageId);
}
catch (System.Exception e)
{
Log.Debug (TAG, "Error displaying message: " + e);
}
}
}
[/sourcecode]
When a message has been received the following code is used to create the pending intent, which will fire when the user selects the notification from the Android notification status bar. For this notification I have chosen to display a message that can be expanded when the user selects it. The other important point here is the messageId is used when displaying the notifications. This ensures a unique notification will be displayed for each account in the status bar. If a notification is delivered with the same ID, then it will replace the existing one.
[sourcecode language=”csharp” highlight=”28″]
private void CreateSystemNotification (string message, int messageId) {
Notification.BigTextStyle textStyle = new Notification.BigTextStyle ();
textStyle.BigText (message);
var intent = new Intent (this, typeof(MainActivity));
intent.AddFlags (ActivityFlags.SingleTop);
intent.AddFlags (ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity (this, 0, intent, PendingIntentFlags.UpdateCurrent);
var notificationBuilder = new Notification.Builder (this)
.SetSmallIcon (Resource.Drawable.app_notifications_status_bar)
.SetContentTitle (ApplicationInfo.LoadLabel(PackageManager)) // app name
.SetContentText (message)
.SetAutoCancel (true)
.SetContentIntent (pendingIntent)
.SetLargeIcon (BitmapFactory.DecodeResource (Resources, Resource.Drawable.agl_launch_icon))
.SetSound (RingtoneManager.GetDefaultUri (RingtoneType.Notification))
.SetStyle (textStyle);
_notificationManager = (NotificationManager)GetSystemService (Context.NotificationService);
_notificationManager.Notify (messageId, notificationBuilder.Build ());
}
[/sourcecode]
To keep track of whether the application is in the foreground I use the following:
[sourcecode language=”csharp”]
public static class CurrentApplicationState
{
private static bool _appIsInForeground;
public static bool appIsInForeground
{
get { return _appIsInForeground; }
set
{
_appIsInForeground = value;
}
}
}
[/sourcecode]
And I call this from my base application:
[sourcecode language=”csharp”]
protected override void OnPause ()
{
base.OnPause ();
CurrentApplicationState.appIsInForeground = false;
}
protected override void OnResume ()
{
base.OnResume ();
CurrentApplicationState.appIsInForeground = true;
}
[/sourcecode]
In order for a user to receive notifications on his/her Android device they’ll need to have Google Play installed. There is no way of avoiding this as we are using the Google Cloud Messaging service! This code can be used to detect if Google Play is installed and on the latest version:
[sourcecode language=”csharp”]
public static bool IsGoogleServicesAvailable ()
{
GoogleApiAvailability googleAPI = GoogleApiAvailability.Instance;
int resultCode = googleAPI.IsGooglePlayServicesAvailable (Context);
if (resultCode != ConnectionResult.Success)
{
return false; // There is an issue with the Google Play version installed on the device
}
return true;
}
[/sourcecode]
Using this implementation you’re relying on Google to provide the messaging. I choose not to inform the customer at this point as the message from Google is fairly blunt. As you can see below it mentions the application won’t run without updating Google play which is not strictly true, as it will run fine! Instead I pop up a message at the point in which they configure the notification service, which happens much deeper in the app than the main activity!
Using the simulator
If, like me, you find it easier to use the Xamarin Android emulator for debugging you’ll need to install Google Play before you can test notifications on the simulator. Download the Gapps package from the following website: http://www.teamandroid.com/gapps/. Simply drag the zip file into the emulator window (this works on a Mac, I’m not sure about Windows?) and follow the on screen prompts to install Google Play.
Log in with a Google account and you’re ready to test your notifications!
Testing the service
In order to make sure things are running as expected you can send a test notification. There are a number of ways to do this but my preference is to use Postman (the Chrome extension) with the following settings:
POST /gcm/send HTTP/1.1
Host: gcm-http.googleapis.com
Authorization: key=[YOUR API KEY]
Content-Type: application/json
Cache-Control: no-cache
And the body of the POST request:
[sourcecode language=”javascript”]
{
"type": "android",
"data": {
"title":
"This is the title of the message",
"message": "You have been served, from the Google Cloud Messaging service.",
"account": 123456789
},
"to" : "eD4ceBas2SN3:APA93THISchdsISsasdNOTqwe9asczAasd98EHsdREALasd0c+KEYv0kx50GZPsyc3ah6_eyvur-wvwVQe6Lfbv5ICijBfYOCkujQK271sK-RmxTe-Y_Aofx1RCe7yfnYgK7MEL7xgqY"
}
[/sourcecode]
Image below for further clarity!
Or if you prefer you can also log into Azure and send a notification from there. In order to send a message to a specific device you will need to set up a server side implementation and then target a device using the “Send to Tag” option. As I only have 1 device activated I can choose Random Broadcast and it will send an alert to my test device.
Summary
Hopefully this will have provided a good taster on how to set up Google Cloud notifications on Android using Microsoft Azure notification hub. In order to target specific devices you’ll need to create a server side API to maintain a dataset of devices and associated tokens. Hopefully if time permits this will be the subject of a future post!
If you’re looking for more information, I found the following sites helpful when setting this up:
The Xamarin Android notification guide: https://developer.xamarin.com/guides/cross-platform/application_fundamentals/notifications/android/remote_notifications_in_android/
Google Cloud Messaging docs: https://developers.google.com/cloud-messaging/
Hi, thanks for sharing this. I’ve achieved similar result using AzureMessaging component (for Android, iOS and UWP). Do you know if there’s any performance/reliability difference between these two solutions?
I’ve not had much hands on experience with the AzureMessaging component.
In terms of performace/reliability I don’t believe there will be any improvement as ultimately Google sends the message, and the Microsoft Notification Hub will be handling the communication between device and GCM.
The main differenciation in my implementation is I am using an existing web API to handle management of tags/tokens in Azure Notification Hub (and rules based on when to send alerts etc). I assume the AzureMessaging component will handle this on device and remove the requirement for an additional API layer.
The one downside to using the AzureMessaging component is the lock in to Azure Notification Hub. With my GCM implementation I am free to change my API to a different notification provider other than MS Notification Hub.
The AzureMessaging component looks to be a simpler implementation, if the additional message tagging control is not required.
It’s also worth considering how the component manages the refresh of tokens. Hopefully AzureMessaging uses the newer Instance ID API and not the deprecated GCM.Register().
This looks great! Is there a way we can get your source code?