Rich actionable push notifications on iOS

rich actionable push notifications

Reading Time: 7 minutes

Push notification is a message or a information that is “pushed” or delivered from server to client application. From its introduction back in 2009., push notifications became more and more powerful and from iOS 10 you can use push notifications for more then sending short message.

In this post we’ll cover rich actionable push notifications or how to send a media attachment inside push notification and provide actions that user can take without opening an app. If you want to know more about push notifications, payload, prerequisites, etc please see this article for more information.

 

Rich push notifications

 
From iOS 10 you can include media attachment to be displayed within push notification. Supported types  of media attachment include image, video, and audio. Of course, there are some limitations, like maximum size or supported file types and you can find more information in Apple’s official documentation.

The first thing you’ll need to do is to create an application on App Store and generate new client SSL certificate and provisioning profile. You can read how to do that in the previous article.

 

Setup Xcode project

 
Now you can open Xcode and create a new project. For bundle identifier enter the same information you entered on Apple Developer portal when you created a new app ID.

Next step is to enable push notifications in our project. Go to Xcode, select target, then Capabilities and turn Push Notifications option on.

push notifications ios firebase
 

Register for push notifications

 
Before we can handle media attachments we need to register for remote notifications. To do this open AppDelegate.

First, add following lines at the top of the file:

import UserNotifications

We need to import a new framework, called UserNotifications, which is responsible for the delivery and handling of local and remote notifications.

After this let’s register our app for remote notifications. Create a new method, registerForNotifications and call it in application:didFinishLaunchingWithOptions: method (also you can put it in applicationWillFinishLaunching method).

func registerForNotifications(_ application: UIApplication) {

        UNUserNotificationCenter. current().delegate = self

        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]

        UNUserNotificationCenter. current(). requestAuthorization(options: authOptions) { (granted, error) in

            print("Permission granted: \(granted)")

        }

        application. registerForRemoteNotifications ()
}

In the code above we’re first assigning our delegate to the UNUserNotificationCenter object to receive display notifications. We need to do this before app finishes launching.

Now we need to fetch the device token.

func application(_ application: UIApplication, didRegisterForRemoteNotificati onsWithDeviceToken deviceToken: Data) {

        let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})

        print(deviceTokenString)

}

And of course, we need to handle an error.

func application(_ application: UIApplication, didFailToRegisterForRemoteNoti ficationsWithError error: Error) {

        print("Remote notifications registration error: \(error)")

}

Start your app on the device and if you configured everything properly you should receive an alert (message) to allow push notifications for the app.

push notifications ios firebase

 

Show a media attachment

 
To display a media attachment in push notification we need to use a notification service extension to modify the content before it is delivered to users.

Reason for this is payload size limitation of push notification. As you may already know maximum payload size of a push notification is 4kb so we can’t embed media file in the push notification. Instead, we’ll add a new key called “media-url” (this is url to your image, video or audio: you can use any key you want, just be sure that you use the same key here and in your code) in a push notification and then handle it in service extension. One more important thing regarding the payload – you must include “mutable-content” key in a payload.This tells OS it should initiate service extension of your app and perform some actions (in this case download and save an image). Your payload should look like this:

{

     aps: {

               “alert”: "Push notification with attachment”,

               “badge":1,

               “sound":"default",

               “mutable-content":1

},

     data:{

               “attachment-url":"https://www. w3schools.com/w3images/fjords. jpg"

    }

}

Create a new Notification Service Extension by selecting File -> New -> Target and then Notification Service Extension.

Fill requested information and click on button “Finish”.

Service extension has two files – NotificationService.swift (this class inherits from UNNotificationServiceExtension ) and Info.plist. So before displaying media attachment, in this case, an image, we first need to download and save an image in our iOS application.

Open NotificationService.swift class and add a code which will download and save an image.

Your class now should look like this :

 override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let content = bestAttemptContent {
            func failEarly() {
                contentHandler(request. content)
            }

            guard let apnsData = content.userInfo["data"] as? [String: Any] else {
                return failEarly()
            }
         
            guard let mediaURLString = apnsData["media-url"] as? String else {
                return failEarly()
            }
            
            guard let mediaURL = URL(string: mediaURLString) else {
                return failEarly()
            }
            
            URLSession.shared. downloadTask(with: mediaURL, completionHandler: { (location, response, error) in
                if let downloadedURL = location {
                    let tempDirectory = NSTemporaryDirectory()
                    let tempFile = "file://".appending( tempDirectory).appending( mediaURL.lastPathComponent)
                    let tempURL = URL(string: tempFile)
                    if let tmpUrl = tempURL {
                        try? FileManager.default.moveItem( at: downloadedURL, to: tmpUrl)                   
                        if let attachment = try? UNNotificationAttachment( identifier: "image.png", url: tmpUrl) {
                            self.bestAttemptContent?. attachments = [attachment]
                        }
                    }
                }
                self.contentHandler!(self. bestAttemptContent!)
            }).resume()
        }
    }

And now let me explain what we are doing in the code above.

First, we are checking the notification’s payload for the dictionary named ‘data’. This dictionary holds a key which represents an url to our image and if this key exists we’re downloading the image from specified URL using URLSession. If the request finishes successfully file is downloaded and url parameter (location) of the completion handler contains the location of the temporary file. Afer that we’re saving an image file to disk and then adding a path of the file to a UNNotificationAttachment and sending back the edited notification to be displayed to our users. UNNotificationAttachment is an object which contains image, video or audio.

 

Send push notification with an image url

 
And now let’s see this in action. We’re going to send a push notification and for this I’m going to use Mac tool called Pusher. It is a tool for sending push notifications to the Apple Push Notification Service and you can download it from GitHub. Payload looks like this:

{
"aps":
      {
          "alert":"Testing.. (16)”,
          "badge":1,
          "sound":"default",
          "mutable-content":1
      }, 
"data":
      {
          "media-url":"https:// www.w3schools.com/w3images/ fjords.jpg"
      }
}

rich actionable push notifications ios

And now you should receive a push notification with an image.

The UI you see in the image above is the default one for notification with media attachment. If you want, from iOS 10, you can customize this UI and to do so you need Notification Content Extension. You add Notification Content Extension the same way you added Notification Service Extension by selecting File -> New -> Target and then selecting Notification Content Extension. Once this is done you get NotificationViewController. swift file, a storyboard and Info.plist file. In this article, we’re not going into details regarding Notification Content Extension but I just wanted to mention it so that you know that you have an option to customize notification UI.

 

Actionable notifications – provide actions the user can take without opening the app

 
When user taps on a notification your app will launch. Instead of the user being forced to launch your app, you can display custom action buttons in the notification which gives users an easy way to perform some task. These notifications are also called actionable notifications.

When a user taps on some action button, notification will be dismissed and selected action will be forwarded to your app.

You need to include key “category” in the payload to display custom actions with push notification. Also inside the app, you need to register categories that include these custom actions.

Payload looks like this:

{
"aps":
     {
         "alert":"Testing.. (16)”,
         "badge":1,
         "sound":"default",
         "mutable-content":1,
         "category":"myCategory"
     }, 
"data":
      {
         "media-url":"https:// www.w3schools.com/w3images/ fjords.jpg"
      }
}

And let’s register our category and add custom actions inside NotificationService class (below code that downloads an image and sends it back to be displayed to users).

let firstAction = UNNotificationAction( identifier: "first", title: "First action", options: [.foreground])           

let secondAction = UNNotificationAction( identifier: "second", title: "Second action", options: [.foreground])

let category = UNNotificationCategory( identifier: "myCategory", actions: [firstAction, secondAction], intentIdentifiers: [], options: [])

UNUserNotificationCenter.current().setNotificationCategories([category])

We’re creating two actions and for this, we’re using UNNotificationAction. We’re passing .foreground option (you can read more here) which causes the app to launch in the foreground. If you want to implement action that won’t open the app but just dismiss notification you can pass .dismiss option.

In AppDelegate add following method.

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

        switch response.actionIdentifier {

        case "first:

            //first action

        case "second":

            //second action

        default:

        }

        completionHandler()

}

Now we can send our push notification with Pusher and you should receive a push notification that looks like this:

 

Conclusion

 
Now you know how to handle media attachments in push notifications and how to provide actions to your users. I hope this article was helpful and useful and that you learned something. If it was please share this article with your friends. And if you have any questions or problems leave me a comment or send me an e-mail.

 

Spread the love

Leave a Reply

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