0 Comments
 

ApplePushOverview

Lets have a look on how we can enable a Xamarin.iOS i.e. Xamarin.Forms app to receive push notifications. I’m using the Azure Notification Hub on the backend which simplifies the integration of the push services on the backend.

Requirements

To implement push notifications on iOS you will need to have:

  1. An apple developer account
  2. An iOS device
  3. An Apple computer you can access
  4. A valid Azure Account

You will need an iOS Device as push notifications can not be tested in the simulator.

Further this blog post will assume that you are using Visual Studio as a development environment.

Setting up the backend

On the backend we will have to do the following steps:

  1. Generate a certificate
  2. Registering your app for push notifications
  3. Configuring the notification portal on Azure

Generating the certificate

For sending push notifications with an apple device we will need to have a Push certificate. The certificate is generated with the Keychain Access tool.

On OSX you can search all the programs by using the finder which you can find at the top right and has the symbol of a magnifying glass.

GenerateCertificate

Select Keychain Access, Certificate Assistantand then Request a Certificate From a Certificate Authority

CertificateDetails

Enter your user Email and common name. And ensure you select save to disk. After selecting continue make give your cert a good name and save it to the desktop.

Registering your app for push notifications

Login to the Apple developer portal, go to the App IDs, select your app and click onto Edit.Create certificate

Select Create Certificate… (for now lets choose the Development SSL Certificate,click onto Continue and under Choose File… select and upload the previously generated certificate.

ConfigurePushNotificaiton

Final step download the generate certificate and double click to import it to your keychain. For Azure we will need to export the cert into a p12 file. So open up Keychain Access. Under Keychainsselect login, then under Category select Keys, now find the Pushcertifiacte (expand it and export the private key) right-click, click Export,choose a good name, select .p12 format and finally click Save.

Make sure that the iOS device you want to use for testing the push notification is added to the app.

Configuring the notification portal on Azure

Now lets first setup the backend so we can send the push notification messages, which will require a valid Azure Account. Log on to Azure and perform the following steps:

  1. Click +NEW
  2. Click APP SERVICES, then SERVICE BUS and then select NOTIFICATION HUB
  3. Enter name, select the region and if you haven't done so already enter your namespace (this option does not appear if you already have created a namespace).

azuremessagehub

After the notification hub is created we will have to configure it for use with Windows Phone Silverlight. Select your notification hub (namespace), which you will find under the SERVICE BUS tab and then select the notification hub you just created.

Under apple notification settings select upload. Upload the p12 file and the password according to what you entered when it was exported. Under Mode select Sandbox for a development certificate or Production for a production certificate. This will depend upon the certificate you upload for the usage.

Setup the client

After setting up the backend we now can connect our app to the push service, as we will be using Azure for the push service we will need to add the Azure Messaging component which you can download by right-clicking on your iOS project then select Get More Components, search for Azure Messaging and add the component to the project.

Registering for notificaitons

Now let’s start wiring up our app to the push service, this is all done in AppDelegate.cs.

First update the FinishedLaunching() method as follows:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Forms.Init();

//Register for remote notifications iOS 8 and higher
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var settings = UIUserNotificationSettings.GetSettingsForTypes(UIUserNotificationType.Sound |
UIUserNotificationType.Alert | UIUserNotificationType.Badge, null);

UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}

//Register for remote notifications iOS 7 and bellow
else
{
const UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert
| UIRemoteNotificationType.Badge
| UIRemoteNotificationType.Sound;

UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}

LoadApplication(new App());
return base.FinishedLaunching(app, options);
}

Please note that the registering has changed starting of iOS 8, depending on which version of iOS you are planning on targeting you might only need one of registrations above. If you aren’t using a Xamarin.Forms app it should look as follows:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
//Register for remote notifications iOS 8 and higher

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

UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}

//Register for remote notifications iOS 7 and lower
else
{
const UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert
| UIRemoteNotificationType.Badge
| UIRemoteNotificationType.Sound;

UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}

return true;
}

To finish of the Registration we add the following member variable within AppDelegate.cs 

private SBNotificationHub Hub { get; set; }

and override the RegisteredForRemoteNotifications() method as follows:

 

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
const string notificationHubConnectionString = "Endpoint=sb://mallibone.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=Gn@bb3rTokenString";
const string notificationHubName = "mallibone";

Hub = new SBNotificationHub(notificationHubConnectionString, notificationHubName);

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

var deviceId = Convert.ToBase64String(deviceToken.ToArray());
var tag = Guid.NewGuid().ToString();
var tags = new List<string> { tag };

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

Receiving push notifications

Now lets make our device vibrate the first time a message is received. Therefore we override the ReceivedRemoteNotification in (as you might have already guessed) AppDelegate.cs:

 

public override void ReceivedRemoteNotification(UIApplication application, NSDictionary notificationData)
{
SystemSound.Vibrate.PlaySystemSound();
}

Sending the message

In the server explorer double click on your notification hub which will open a window that allows you to send push notifications and check on your device registrations (all within VS :)). Now under type select Apple (APNS)and then Default. For now we do not have to alter the message so if your app successfully started and is humming beside you just click on Send.

Receiving notifications in the background

In many apps you want to handle waking from a push notification differently then when a notification arrives while the user is using the app e.g. when waking from a push notification we want to navigate directly to where the action originated from, when the app is running we might simply want to notify the user that something happened by vibrating the device.

For handling waking up from a push notification we have to add the RecievedRemoteNotification method as follows:

public override void ReceivedRemoteNotification(UIApplication application, NSDictionary notificationData)
{
if (application.ApplicationState == UIApplicationState.Inactive
|| application.ApplicationState == UIApplicationState.Background)
{
// Handle notification on wake
return;
}

SystemSound.Vibrate.PlaySystemSound();
}

 

Starting the app on a notification

To make thing interesting wake and startup have to handled differently on iOS so to ensure a consistent behaviour between wake and startup we will have to modify the FinishedLaunching method as follows:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();

if (options != null && options.ContainsKey(UIApplication.LaunchOptionsRemoteNotificationKey))
{
var notificationData = options[UIApplication.LaunchOptionsRemoteNotificationKey] as NSDictionary;
// process notification data
}

LoadApplication(new App());
return base.FinishedLaunching(app, options);
}

If you are using Xamarin Forms be sure that you call LoadApplication after handling the notification.

Adding parameters to the notification

Adding parameters is a great way to pass application specific information to the app that is not intended for the user. Adding parameters to the message can be done easily be extending the message as shown in this sample:

{"aps":{"alert":"Notification Hub test notification"},"parameterOne":"SomeIdentifier","parameterTwo":"1234"}

The parameters parsed in ReceivedRemoteNotification:

public override void ReceivedRemoteNotification(UIApplication application, NSDictionary notificationData)
{
if (application.ApplicationState == UIApplicationState.Inactive
|| application.ApplicationState == UIApplicationState.Background)
{
// Handle notification on wake
return;
}


var parameeterOne = notificationData["parameterOne"].ToString();
var parameterTwo = Convert.ToInt32(notificationData["parameterOne"].ToString());

// Send message i.e. process push notification


SystemSound.Vibrate.PlaySystemSound();
}

And in FinishedLaunching method:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();

if (options != null && options.ContainsKey(UIApplication.LaunchOptionsRemoteNotificationKey))
{
var notificationData = options[UIApplication.LaunchOptionsRemoteNotificationKey] as NSDictionary;
var parameeterOne = notificationData["parameterOne"].ToString();
var parameterTwo = Convert.ToInt32(notificationData["parameterOne"].ToString());

// Send message i.e. process push notification
// process notification data
}

LoadApplication(new App());
return base.FinishedLaunching(app, options);
}

 

Conclusion

Adding push notifications for a Xamarin.iOS or Xamarin.Forms app is possible and with Azure as the backend will allow you to streamline the integration for other platforms such as Windows Phone or Android.

Post comment