Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

Notification Service Extensions Tutorial

Introduction

Notification Service Extensions allow you to modify the content of a remote notification before it is delivered to the user. This is useful for decrypting data, downloading images, or any other content updates. In this tutorial, we will walk you through setting up a Notification Service Extension in an iOS app.

Creating a Notification Service Extension

To create a Notification Service Extension, follow these steps:

  1. Open your Xcode project.
  2. Go to File > New > Target...
  3. Select Notification Service Extension and click Next.
  4. Provide a name for your extension (e.g., NotificationService) and click Finish.

Xcode will create a new target with a default implementation. This includes a subclass of UNNotificationServiceExtension.

Modifying the Notification Content

The main class you will work with is NotificationService. This class contains methods to handle the notification. The most important method is:

didReceive(_:withContentHandler:)

Here is an example of how you could modify the notification content:


import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            // Modify the notification content here...
            bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
            
            contentHandler(bestAttemptContent)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}
            

Testing the Extension

To test your Notification Service Extension, you can use a real device and send a push notification. Here is an example of a payload you might use:


{
    "aps": {
        "alert": {
            "title": "Hello",
            "body": "World"
        },
        "mutable-content": 1
    }
}
            

Ensure that the mutable-content flag is set to 1. This tells iOS to use your Notification Service Extension to modify the notification.

Handling Media Attachments

One common use case for Notification Service Extensions is to handle media attachments, such as images or videos. Here is an example of how you can download and attach an image:


import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent, let attachmentURLString = request.content.userInfo["attachment-url"] as? String, let attachmentURL = URL(string: attachmentURLString) {
            downloadImage(from: attachmentURL) { attachment in
                if let attachment = attachment {
                    bestAttemptContent.attachments = [attachment]
                }
                contentHandler(bestAttemptContent)
            }
        } else {
            contentHandler(bestAttemptContent ?? request.content)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }

    private func downloadImage(from url: URL, completion: @escaping (UNNotificationAttachment?) -> Void) {
        let task = URLSession.shared.downloadTask(with: url) { (downloadedUrl, response, error) in
            guard let downloadedUrl = downloadedUrl else {
                completion(nil)
                return
            }
            let attachment: UNNotificationAttachment
            do {
                attachment = try UNNotificationAttachment(identifier: "", url: downloadedUrl, options: nil)
            } catch {
                completion(nil)
                return
            }
            completion(attachment)
        }
        task.resume()
    }
}
            

Conclusion

Notification Service Extensions are a powerful way to customize the content of your notifications. You can modify text, handle media attachments, and perform other tasks to enhance the user experience. We hope this tutorial has provided a comprehensive guide to getting started with Notification Service Extensions in iOS development.