NotifyMe – Push notifications

Today I want to show you how to configure and use push notifications on Android platform using Notification Hub and Firebase.

In the beginning we have to create new Microsoft Azure component via portal:

Select Notification Hub component in Web + Mobile category.

and as always fill the form which is presented below.

In the newly created component go to Notification Services section:

Then you have to select which notification service you want to configure. In our case (Android) it is Google (GCM).

After selection Azure will ask you for API key.

To get key, login into Firebase console and create new project for your application. You can read more about Firebase features here.

Open project settings. If you are first time on Firebase website that can be tricky 🙂 There is a really small settings icon.

Go to Cloud Messaging tab. There is everything what you are looking for – Project credentials.

Copy Server Key and paste it into GCM configuration in Azure as Api key. You have to also save Sender ID – we will use it later in code.

Configuration is done. It’s time for coding.

Add Google Cloud Messeging Client component to your Droid project.

If you want to send notification to specific user you have to register twice. The first registration is for user’s device in GCMClient, the second one is specific user account registration by tag in Notification Hub.

However before any registration add these following bunches of code into your project:

    [BroadcastReceiver(Permission = Constants.PERMISSION_GCM_INTENTS)]
    [IntentFilter(new string[] { Constants.INTENT_FROM_GCM_MESSAGE }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { Constants.INTENT_FROM_GCM_LIBRARY_RETRY }, Categories = new string[] { "@PACKAGE_NAME@" })]
    public class PushHandlerBroadcastReceiver : GcmBroadcastReceiverBase<GcmService>
    {
        public static string[] SenderIds = new string[] { "<SENDER ID>" }; // fill with your sender id from firebase project
    }
[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")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
namespace NotifyMe.App.Droid
{
    [Service]
    public class GcmService : GcmServiceBase
    {
        public static string RegistrationID { get; private set; }

        public GcmService()
            : base(PushHandlerBroadcastReceiver.SenderIds) { }

        protected override void OnRegistered(Context context, string registrationId)
        {
            RegistrationID = registrationId;

            DeviceRegistration registration = new DeviceRegistration();
            registration.Handle = registrationId;
            registration.Tag = MobileServiceClientWrapper.Instance.CurrentUser.Id;
            var serialized = JsonConvert.SerializeObject(registration);

            var jtoken = JToken.Parse(serialized);

            StringContent content = new StringContent(serialized);

			Task.Run(async () => 
			         await MobileServiceClientWrapper.Instance.Client.InvokeApiAsync("notifications/register", jtoken, HttpMethod.Post, null));
        }

        protected override void OnMessage(Context context, Intent intent)
        {
            string message = intent.Extras.GetString("message");
            string subject = intent.Extras.GetString("subject");
            if (!string.IsNullOrEmpty(message))
            {
                CreateNotification(this, subject, message);
                return;
            }
        }

        private void CreateNotification(GcmService instance, string subject, string message)
        {
            var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;

            var uiIntent = new Intent(instance, typeof(MainActivity));

            NotificationCompat.Builder builder = new NotificationCompat.Builder(instance);
            var notification = builder.SetContentIntent(PendingIntent.GetActivity(instance, 0, uiIntent, PendingIntentFlags.OneShot))
			        .SetSmallIcon(Resource.Drawable.icon)
                    .SetStyle(new NotificationCompat.BigTextStyle().BigText(message))
                    .SetAutoCancel(true)
                    .SetContentTitle(subject)
                    .SetContentText(message)
                    .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))
                    .SetAutoCancel(true).Build();

            notificationManager.Notify((int)DateTime.Now.Ticks, notification);
        }

        protected override void OnUnRegistered(Context context, string registrationId)
        {
            Log.Error("PushHandlerBroadcastReceiver", "Unregistered RegisterationId : " + registrationId);
        }

        protected override void OnError(Context context, string errorId)
        {
            Log.Error("PushHandlerBroadcastReceiver", "GCM Error: " + errorId);
        }
    }

To register call these methods in OnCreate method in your MainActivity:

 GcmClient.CheckDevice(this);
 GcmClient.CheckManifest(this);
 GcmClient.Register(this, PushHandlerBroadcastReceiver.SenderIds);

OnRegistered method is called after successful device registration. There is a place for second registration in notification hub.
You can achieve it from mobile device, but registration can be also executed on server side.
If you are using Mobile App Microsoft Azure component like me , you can call your API by calling InvokeApiAsync method in MobileServiceClient class.
My whole API controller for sending notifications and registrations in Notification Hub is presented below.

    [MobileAppController]
    public class NotificationsController : ApiController
    {
        string connectionString = "<YOUR-CONNECTION-STRING>";
        string notificationHubName = "<YOUR_NOTIFICATIONHUB_NAME>";

        private NotificationHubClient hub;

        public NotificationsController()
        {
            hub = NotificationHubClient.CreateClientFromConnectionString(connectionString, notificationHubName);
        }

        [Route("api/notifications/register")]
        [HttpPost]
        public async Task<IHttpActionResult> Register([FromBody] DeviceRegistration device)
        {
            RegistrationDescription registration = new GcmRegistrationDescription(device.Handle);

            var registrationId = await CreateRegistrationId(device.Handle);

            registration.RegistrationId = registrationId;
            registration.Tags = new HashSet<string>() { device.Tag };

            try
            {
                await hub.CreateOrUpdateRegistrationAsync(registration);
                return Ok();
            }
            catch (MessagingException ex)
            {
                return InternalServerError(ex);
            }
        }

        [Route("api/notifications/send")]
        [HttpPost]
        public async Task<IHttpActionResult> Send([FromBody] Message message)
        {
            try
            {
                var registrations = await hub.GetRegistrationsByTagAsync(message.RecipientId, 100);

                NotificationOutcome outcome;

                if (registrations.Any(r => r is GcmRegistrationDescription))
                {
                    var notif = "{ \"data\" : {\"subject\":\"Message from " + message.From + "\", \"message\":\"" + message.Body + "\"}}";
                    outcome = await hub.SendGcmNativeNotificationAsync(notif, message.RecipientId);
                    return Ok(outcome);
                }

                return NotFound();
            }
            catch (Exception ex)
            {
                return InternalServerError(ex);
            }
        }

        private async Task<string> CreateRegistrationId(string handle = null)
        {
            string newRegistrationId = null;

            if (handle != null)
            {
                var registrations = await hub.GetRegistrationsByChannelAsync(handle, 100);

                foreach (RegistrationDescription registration in registrations)
                {
                    if (newRegistrationId == null)
                    {
                        newRegistrationId = registration.RegistrationId;
                    }
                    else
                    {
                        await hub.DeleteRegistrationAsync(registration);
                    }
                }
            }

            if (newRegistrationId == null)
                newRegistrationId = await hub.CreateRegistrationIdAsync();

            return newRegistrationId;
        }
    }

After calling api/notifications/send endpoint you will receive push notification!

Status bar:

and notification body:

If you have some troubles during following my instructions feel free to contact me using this form Contact.
I will answer your questions with pleasure.

In next post I will tell you something about Custom Renderers which I had to write.
Be patient, I will also show you how to configure push notifications for iOS device soon.

Leave a Reply

Your email address will not be published. Required fields are marked *