Xamarin.iOS Push Notifications – part II

In previous post about push notifications in Xamarin.iOS – here, I showed you how to configure push notifications in Apple developer account and Microsoft Azure Notification hub. There was a lot of work to do, generating certificates, creating provisioning profiles etc. Today I want to present you what you can do with it.

Similar to Xamarin.Android flow you have to register device for receiving notifications. Use the following code in FinishedLaunching method in AppDelegate class.

if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
    var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
		                                   UIUserNotificationType.Alert | 
                                                   UIUserNotificationType.Badge | 
                                                   UIUserNotificationType.Sound,
		                                   new NSSet());

    UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
    UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
    UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | 
                                                 UIRemoteNotificationType.Badge | 
                                                 UIRemoteNotificationType.Sound;

    UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}

Then you have to override RegisteredForRemoteNotifications and ReceivedRemoteNotification methods.

        public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
        {
            var Hub = new SBNotificationHub("<YOUR-CONNECTION-STRING>", "<HUB-NAME>");

            Hub.UnregisterAllAsync(deviceToken, (error) =>
            {
                if (error != null)
                {
                    Console.WriteLine("Error calling Unregister: {0}", error.ToString());
                    return;
                }

                NSSet tags = new NSSet(MobileServiceClientWrapper.Instance.CurrentUser.Id);
                Hub.RegisterNativeAsync(deviceToken, tags, (errorCallback) =>
                {
                    if (errorCallback != null)
                        Console.WriteLine("RegisterNativeAsync error: " + errorCallback.ToString());
                });
            });
        }

        public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
        {
            ProcessNotification(userInfo);
        }

As you can see registration in Notification Hub is handled in device instead of server so iOS devices will only use endpoint for sending.
To identificate a specific user you can use a tags. In my application tag is an id of current logged user in facebook service.

Of course you have to also write a method for creating notifications and parse payload.

        void ProcessNotification(NSDictionary options)
        {
            var apsObj = new NSString("aps");

            if (null != options && options.ContainsKey(apsObj))
            {
                NSDictionary aps = options.ObjectForKey(apsObj) as NSDictionary;

                string subject = string.Empty;
                string message = string.Empty;

                if (aps.ContainsKey(new NSString("subject")) && aps.ContainsKey(new NSString("message")))
                {
                    subject = (aps[new NSString("subject")] as NSString).ToString();
                    message = (aps[new NSString("message")] as NSString).ToString();

                    if (!string.IsNullOrEmpty(subject) && !string.IsNullOrEmpty(message))
                    {
                        UIAlertView avAlert = new UIAlertView(subject, message, null, "OK", null);
                        avAlert.Show();
                    }
                }
            }
        }

and write some server code if your receiver has iOS device.

       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);
                }

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

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

Now it is time to test it. If you already registered your device you can use Microsoft Azure portal to send test notifications.
In notification hub component go to Test Send section.

Select a platform: Windows Phone, Android, Apple, Windows or Custom Template
And write your payload.
Please note that, aps element in payload for Apple is obligatory.

If you want to send test notification to specific user / device fill tag field in form. If you leave it empty push notification will be sent to 10 random registrations on the selected platform.

Important thing is that you have to set the same bundle identifier for your application and App ID in Apple developer account.
In my case it is:

If you configured everything properly push notifications in your iOS device should work perfectly like in mine. Enjoy!

Leave a Reply

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