Push Notifications: Adding rich content in iOS 10

Our Push Notifications system is currently in beta. This means you may experience errors, and the APIs may change. We would love to hear your feedback, so please get in touch!

With iOS 10, you can now send rich media in a Push Notification, including images, GIFs, audio, and video clips.

You should already have an iOS app which you would like to configure. For more on setting up an iOS app with Pusher, see our iOS Quick Start guide.

Sending rich notifications in iOS 10 using the Native Push Notifications API

Update your version of the PusherSwift CocoaPod to version 3.0.0.

pod 'PusherSwift'

Go to your application target and choose Capabilities and ensure that ‘Push Notifications’ is enabled and that ‘Remote notifications’ is selected under Background Modes.

Swift 3 introduces some changes to the methods for registering your applications for remote notifications. The syntax is also a little different in places.

In AppDelegate.swift, add import UserNotifications and in the didFinishLaunchingWithOptions method, use the following code to register for remote notifications, which has been updated in Swift 3:

let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
	// actions based on whether notifications were authorized or not
}
application.registerForRemoteNotifications()

You’ll also need to replace your code in didRegisterForRemoteNotificationsWithDeviceToken with:

pusher.nativePusher().register(deviceToken: deviceToken)
pusher.nativePusher().subscribe(interestName: "donuts")

Notification Service Extension

A Notification Service Extension intercepts certain remote notifications and allows your application to handle the contents of the payload, including downloading and displaying remote media attachments, before displaying the notification to the user.

Add a new Notification Service Extension target by going to File > New > Target.

Open the new NotificationService.swift file and add the following code to the didReceiveRequestWithContentHandler method:

self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

// Get the custom data from the notification payload
if let notificationData = request.content.userInfo["data"] as? [String: String] {
    // Grab the attachment
    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: "", url: tmpUrl) {
                    self.bestAttemptContent?.attachments = [attachment]
                }
            }
            // Serve the notification content
            self.contentHandler!(self.bestAttemptContent!)
            }.resume()
    }
}

In this code, we are exploring the notification’s payload for the dictionary named data that contains the key attachment-url. If this key exists, we download the media at the URL specified in the key’s value.

The URLSession downloads the media to temporary storage and appends a .tmp file extension, which needs to be removed so that the application can infer the file type and display it. This is done by moving the temporary file to the device’s File Manager.

APNs Payload

You’ll need to make a couple of adjustments to the server that triggers Push Notifications to your application.

Your APNs payload tells iOS which notifications will be intercepted by the Notification Service Extension by using the new mutable-content key, which takes the value 1 to enable it.

You then need to include whatever media attachment you choose to use in the payload by including it in its own dictionary that we’ve named data, but you can name anything. Add a key-value pair to the dictionary, ensuring that the key you’ve used in your Notification Service Extension is the same as the key here.

The following example is using a Node JS server:

pusher.notify(['donuts'], {
  apns: {
    aps: {
      alert: {
        title: "Pusher's Native Push Notifications API",
        subtitle: "Bringing you iOS 10 support!",
        body: "Now add more content to your Push Notifications!"
        },
        "mutable-content": 1,
        category: "pusher"
      },
    data: {
      "attachment-url": "https://pusher.com/static_logos/320x320.png"
    }
  },
  webhook_url: "https://example.com/endpoint",
  webhook_level: "INFO"
});

You will now be able to send images, videos, audio, and GIFs in your iOS 10 Push Notifications! Simply change the URL to point to another media file when required.

You can remove the media attachment and send text only.

How do I add a custom UI to my notifications in iOS 10?

You can also design your own views within your push notifications using Notification Content Extensions. These are used to draw your own UI to display when your application receives certain notifications.

Add a new Notification Content Extension target by going to File > New > Target.

The Content Extension uses a NotificationViewController, which is a subclass of UIViewController.

When you created the Content Extension, Xcode created the NotificationViewController.swift file, a MainInterface.storyboard file and an Info.plist file.

Expand the NSExtension and NSExtensionAttributes dictionaries in the Info.plist file.

The UNNotificationExtensionCategory key value is the same as the value set in the Node JS server example above. This tells iOS that the push notification you’re triggering is of a certain category, and should be handled in a certain way. In this case, with a Content Extension. Make sure this matches the category set in the push notification payload.

The key UNNotificationExtensionInitialContentSizeRatio relates to the size of the view that is displayed when your push notification is expanded. By default, this is 1. You should experiment with this to get the best results for your UI.

Add the 3rd key UNNotificationExtensionDefaultContentHidden. This key is a boolean, and either hides or displays the push notification’s alert text.

In MainInterface.storyboard, create the UI that your push notifications will display, just like a regular UIViewController.

In NotificationViewController.swift, declare any IBOutlets and connect them to the Storyboard file.

Assign values to the outlets in the didReceiveNotification method, like this example:

func didReceive(_ notification: UNNotification) {
    titleLabel?.text = notification.request.content.title
    subtitleLabel?.text = notification.request.content.subtitle
}

Trigger a Push Notification using our API, making sure the category matches, and you’ll see your custom UI when you expand the push notification.

That’s it! You’re all set up to send and receive rich notifications in iOS 10! Here you will find a complete tutorial of rich Push Notifications in iOS 10.

Have you tried using the search to find what you’re after? If you still have a question then get in touch with us and let us help you out.