Launching support for iOS 10 Rich Push Notifications

  • Sep 21, 2016
  • Messaging
  • iOS 10
  • Push Notifications

For the first time, in iOS 10, marketers are allowed to add rich content into their push notifications for iPhones and iPads. This new rich content includes images, html, video and even GIF files.

Also you can take immediate actions when you expand a push notification. This means you can now reply to a chat message without opening the app, just to give a simple example.

To start using iOS 10 push notifications in your app you need to have a Realtime Messaging subscription. You can get yours here.

The next step is to get your APNS certificate and register it in your Realtime Messaging subscription (if you already have an iOS app using push notifications with Realtime you can skip this step).

The best way to build your first app using Realtime Push Notifications for iOS is to follow this guide. In the end come back to this blog post for the iOS 10 specifics.

When you're ready jump to the next section to learn how to send and receive the new rich notifications.

Sending rich notifications with Realtime

Assuming that you have your iOS app ready using the automatic Realtime Push Notifications, sending the new rich notifications only requires a few changes in your app code and the use of the Realtime Custom Push Notifications API through a HTTP POST.

Let's start with the Realtime Custom Push Notifications API usage, so you can get a feeling for the payload request you need to use to send a rich notification.

The notification request payload

Below you'll find a simple example of a request payload sending a rich notification with a mp4 video to all the devices subscribing the notification channel:

{
  	"applicationKey": "YOUR_REALTIME_APPKEY",
  	"privateKey": "YOUR_REALTIME_PRIVATEKEY",
  	"channel" : "notification",
  	"apns": {
  		"aps":{
  			"alert":{
  				"title":"Realtime Custom Push Notifications",
  				"subtitle":"Now with iOS 10 support!",
  				"body":"Add multimedia content to your notifications"
  			},
  			"sound":"default",
  			"badge": 1,
  			"mutable-content": 1,
            "data":{
                "attachment-url":"https://framework.realtime.co/blog/img/ios10-video.mp4"
            }
  		}
  	}
}

This request payload should be sent as a POST to the following API endpoint:

https://ortc-mobilepush.realtime.co/mp/publish

Here's how to do it using cURL (don't forget to enter your Realtime subscription credentials):

curl -X POST -d '{
  	"applicationKey": "YOUR_REALTIME_APPKEY",
  	"privateKey": "YOUR_REALTIME_PRIVATEKEY",
  	"channel" : "notification",
  	"apns": {
  		"aps":{
  			"alert":{
  				"title":"Realtime Custom Push Notifications",
  				"subtitle":"Now with iOS 10 support!",
  				"body":"Add multimedia content to your notifications"
  			},
  			"sound":"default",
  			"badge": 1,
  			"mutable-content": 1,
  			"category": "realtime",
            "data":{
                "attachment-url":"https://framework.realtime.co/blog/img/ios10-video.mp4"
            }
  		}
  	}
}' "https://ortc-mobilepush.realtime.co/mp/publish"

You probaly noticed the apns property of the request payload. Here you can configure the details of your APNS notification.

The important ones for the rich features are the following:

  • mutable-content
    This indicates a rich notification and will cause iOS to intercept your notification and send it to your app Service Extension (more on this below).
  • attachment-url
    This will contain the media attachment URL of your push notification. In this example we are using a data object with an attachment-url key but you can use any format you want. The important part is that you use the same dictionary key that you will be using in your Service Extension (we'll cover the Service Extension part in the next section).
    Obviously the attachment URL must be publicly available since it will be downloaded by the device.

You can also add other custom keys to the apns dictionary and handle them in your code as you see fit.

The new Notification Service Extension

In the previous section we've mentioned a few times that you need to add a Service Extension to your Xcode project. This is brand new! Let's dig into it.

In your Xcode project choose File > New > Target and select Notification Service Extension.

The Notification Service Extension will "intercept" all remote notifications with the mutable-content key and will allow you to handle the contents of the request payload, including downloading and displaying the media attachments before the notification is displayed to the user.

In this blog post we are assuming you are using Swift 3 but nothing stops you from using Swift 2 or Objective-C if you prefer, but be aware that you may run into issues using those "legacy" languages.

So, now you have a new file called NotificationService.swift. If you open it you'll see two delegate methods. The most important one is the first, didReceive:_Request:WithContentHandler.

In this delegate method you will receive the notification request. Basically you'll need to look for the data dictionary that contains the attachment-url key so you can download it (see the request payload above).

The Swift 3 code for these actions looks like this:

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    self.contentHandler = contentHandler
    bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
    
    // Get the custom data from the notification payload
    if let data = request.content.userInfo["aps"] as? [String: AnyObject] {
        // Grab the attachment
        let notificationData = data["data"] as? [String: String]
        if let urlString = notificationData?["attachment-url"], let fileUrl = URL(string: urlString) {
            // Download the attachment
            URLSession.shared.downloadTask(with: fileUrl) { (location, response, error) in
                if let location = location {
                    // Move temporary file to remove .tmp extension
                    let tmpDirectory = NSTemporaryDirectory()
                    let tmpFile = "file://".appending(tmpDirectory).appending(fileUrl.lastPathComponent)
                    let tmpUrl = URL(string: tmpFile)!
                    try! FileManager.default.moveItem(at: location, to: tmpUrl)
                    
                    // Add the attachment to the notification content
                    if let attachment = try? UNNotificationAttachment(identifier: "video", url: tmpUrl, options:nil) {
                        self.bestAttemptContent?.attachments = [attachment]
                    }
                }
                // Serve the notification content
                self.contentHandler!(self.bestAttemptContent!)
                }.resume()
        }
    }
}

After entering this code into your Service Extension build the app and try sending the request payload from the previous section.

If everything's in order you'll get a push notification with a small thumbnail of the video on the right. Expand it by dragging down the notification and the video will become visible.

Please note that since the video is being downloaded to the device, the notification can take more than the usual time to appear in the screen. This obviously depends on the size of the attachment and on the network bandwidth available in the device.

Great, right? But remember, with great freedoom comes great responsibility, so use these new features wisely.

A note about multi-platform notifications

A great thing about Realtime is that you can have both iOS and Android devices subscribing to the same channel. So how do you send different notification payloads for iOS and Android devices using the same request? Is this even possible?

Sure! And it's very simple. Just add a new key named gcm to the request payload with the payload to send to Android devices subscribing the channel. The key is named gcm but you can use it also for Firebase Cloud Messaging projects.

Here's a simple example of the previous iOS rich notification also with a GCM/FCM payload:

{
  	"applicationKey": "YOUR_REALTIME_APPKEY",
  	"privateKey": "YOUR_REALTIME_PRIVATEKEY",
  	"channel" : "notification",
  	"apns": {
  		"aps":{
  			"alert":{
  				"title":"Realtime Custom Push Notifications",
  				"subtitle":"Now with iOS 10 support!",
  				"body":"Add multimedia content to your notifications"
  			},
  			"sound":"default",
  			"badge": 1,
  			"mutable-content": 1,
            "data":{
                "attachment-url":"https://framework.realtime.co/blog/img/ios10-video.mp4"
            }
  		}
  	},
  	"gcm": {
  		"data": {
  			"M": "Realtime Custom Push Notifications",
  			"foo": "bar"
  		}
  	}
}

In this example we are sending two keys in the GCM data payload: M and foo. These can be anything you want, simply look for the right keys in your Java code when you receive the notification. You are in control!

The Swift 3 Chat example

There's nothing like a working project to get you started, so we have pushed to Github a Swift 3 version of our group chat example, including the new iOS 10 rich notifications support.

Go ahead and clone it from https://github.com/realtime-framework/MessagingSwift3Chat

Have fun pushing!

If you find this interesting please share: