Set up rich push

Updated

Set up your app to support push notifications with images and deep links.

1. Add a service extension to your project

Add a Service App Extension to your project in Xcode.

You should now see a new file added to your Xcode project. The file is probably named NotificationService and looks similar to this.

import UserNotifications
   
class NotificationService: UNNotificationServiceExtension {
   
    override func didReceive(
        _ request: UNNotificationRequest,
        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
    ) {
   
    }
   
    override func serviceExtensionTimeWillExpire() {
   
    }
}

2. Update the service extension

 Xcode 16.3+ users

If you encounter errors like “not available due to missing import of defining module ‘CioMessagingPush’”, go to your NotificationServiceExtension target’s Build Settings and set Member Import Visibility (SWIFT_MEMBER_IMPORT_VISIBILITY) to “Package” or disable it.

Modify your new NotificationService extension by selecting the push package you want to import and calling the appropriate Customer.io functions. Your code changes if:

  • Customer.io is your only push/rich push provider
  • Customer.io is not your only provider
  • You want to take advantage of push features outside the Customer.io, like action buttons; in this case, you’ll need to set your own completion handler.

 App Groups for delivery tracking

The code samples below include a commented-out .appGroupId() line. To improve push delivery metric reliability, set up App Groups and enable that line with your App Group identifier.
// Keep the import for your push provider—FCM or APN, and
// remove the other import statement
import CioMessagingPushAPN 
import CioMessagingPushFCM 
import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
       // Use `MessagingPushFCM` if you are using FCM as push service provider
       MessagingPushAPN.initializeForExtension(
            withConfig: MessagingPushConfigBuilder(cdpApiKey: "YOUR_CDP_API_KEY")
                // Optional: specify region where your Customer.io account is located (.US or .EU). Default: US
                .region(.US)
                // Optional: set App Group ID for reliable push delivery tracking
                // .appGroupId("group.com.example.myapp.cio")
                .build()
       )

       MessagingPush.shared.didReceive(request, withContentHandler: contentHandler)
    }

    override func serviceExtensionTimeWillExpire() {
        MessagingPush.shared.serviceExtensionTimeWillExpire()
    }
}
// Keep the import for your push provider—FCM or APN, and
// remove the other import statement
import CioMessagingPushFCM
import CioMessagingPushAPN
import UserNotifications
   
class NotificationService: UNNotificationServiceExtension {
   
    override func didReceive(
        _ request: UNNotificationRequest,
        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
    ) {
        // Due to the behavior of Notification Service Extensions in iOS, you need to 
        // initialize the Push Module in both your host app and in your Notification Service.         
        // The config builder also lets you you to configure the push module.
       // Use `MessagingPushFCM` if you use FCM as your push service provider
       MessagingPushAPN.initializeForExtension(
            withConfig: MessagingPushConfigBuilder(cdpApiKey: "YOUR_CDP_API_KEY")
                .autoTrackPushEvents(true)
                // Optional: specify region where your Customer.io account is located (.US or .EU). Default: US
                .region(.US)
                // Optional: set App Group ID for reliable push delivery tracking
                // .appGroupId("group.com.example.myapp.cio")
                .build()
       )

        // If you use a service other than Customer.io to send rich push,
        // you can check if the SDK handled the rich push for you. If it did not, you
        // know that the push was *not* sent by Customer.io and you can try another way.
        let handled = MessagingPush.shared.didReceive(request, withContentHandler: contentHandler)
        if !handled {
            // Rich push was *not* sent by Customer.io. Handle the rich push in another way.
        }
    }
   
    override func serviceExtensionTimeWillExpire() {
        MessagingPush.shared.serviceExtensionTimeWillExpire()
    }
}
// Keep the import for your push provider—FCM or APN, and
// remove the other import statement
import CioMessagingPushFCM
import CioMessagingPushAPN
import UserNotifications
import CioDataPipelines
   
class NotificationService: UNNotificationServiceExtension {
   
    override func didReceive(
        _ request: UNNotificationRequest,
        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
    ) {
        // Due to the behavior of Notification Service Extensions in iOS, you need to 
        // initialize the Push Module in both your host app and in your Notification Service.         
        // The config builder also lets you you to configure the push module.
        // Use `MessagingPushFCM` if you use FCM as your push service provider
       MessagingPushAPN.initializeForExtension(
            withConfig: MessagingPushConfigBuilder(cdpApiKey: "YOUR_CDP_API_KEY")
                .autoTrackPushEvents(true)
                // Optional: specify region where your Customer.io account is located (.US or .EU). Default: US
                .region(.US)
                // Optional: set App Group ID for reliable push delivery tracking
                // .appGroupId("group.com.example.myapp.cio")
                .build()
       )

        // If you need to add features, like showing action buttons in your push, 
        // you can set your own completion handler.
        MessagingPush.shared.didReceive(request) { notificationContent in
            if let mutableContent = notificationContent.mutableCopy() as? UNMutableNotificationContent {
                // Modify the push notification like adding action buttons!
            }
            contentHandler(notificationContent)
        }
    }
   
    override func serviceExtensionTimeWillExpire() {
        MessagingPush.shared.serviceExtensionTimeWillExpire()
    }
}

Your app can now display rich push notifications in your app, including images, etc. See Deep Links to enable deep links in your push notifications.

Improve delivery metrics with App Groups

For the most reliable push delivery tracking, set up App Groups for push tracking. App Groups let the SDK recover delivery metrics that iOS might otherwise discard when it terminates the Notification Service Extension. Without this setup, you may lose some delivery data.

Copied to clipboard!
  Contents
Version