Content Extension Custom Events

A content extension can provide a custom interface when a user previews your notification in the notification center. Content extensions provide a great user experience because they're integrated with the notification center and run in a process independent of the main application. Sometimes, however, it's necessary for the main application to receive feedback when a content extension is displayed. This guide demonstrates how to create a content extension that can pass data into a custom analytics event to be uploaded by the main application.

Create a Content Extension

Add a Notification Content Extension target to your application by selecting File -> New -> Target... and then selecting the Notification Content Extension icon in the Application Extension section:

Customize Your Content Extension View

When the content extension target is created, a view controller and storyboard are generated. These can be edited to display a custom interface when your push notification is opened in the system notification center.

Add Extension Attributes

A separate Info.plist file will be generated for your extension when you add your Content Extension target. For your extension to work properly, there are a couple keys that are important to have in your content extension's Info.plist:

UNNotificationExtensionCategory set to <Your Category> : The category allows the system to select you extension for display.

UNNotificationExtensionUserInteractionEnabled set to true : This allows your extension to receive touch events from the user. Note: This functionality is only available in iOS 12 and above.

When you are finished adding attribute keys - your extension's Info.plist should look something like this:

Create and Set Your Category

In your AppDelegate's application:didFinishLaunchingWithOptions: callback, initialize and set a category that matches the category you set under the UNNotificationExtensionCategory key in your extension's Info.plist:

// Define your category
let category = UANotificationCategory(identifier: "<Your Category>",
actions: [],
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder: "Sensitive Content Hidden",
options: [])

// Set your custom categories
UAirship.push().customCategories = [category]

Pass Custom Event Data To Main Application

Custom events can only be created and added to analytics inside the main application. This means any custom event data originating in the content extension must be passed to the main application before being initialized into a custom event and added to analytics. This can be accomplished by using user defaults and an app group. An app group allows sharing a user defaults directory between two or more targets. This allows the content extension to save custom event data as it is generated and for the main application to retrieve and send it when it launches.

Add an App Group

An app group can be added by following these steps:

  • Visit the Apple developer portal in a web browser
  • Navigate to the Certificates, Identifiers & Profiles section
  • Select App Groups under the Identifiers sidebar menu.
  • Select the add (+) button and add your app group i.e. "group.com.yourdomain.yourapp"

Once your app group is added you'll need to repeat the following steps inside Xcode for both your main application and your content extension target:

  • Select your target
  • Open the Capabilities tab
  • Flip the App Groups switch to the ON position
  • Check the corresponding app group

Save Custom Event Data

When your content extension is opened, the UNNotificationContentExtension protocol's application:didReceive callback will be called in your content extension's generated view controller. In this callback, custom event data can be generated and saved to the group user defaults directory. In your content extension's application:didReceive callback, add the following:

let customEventsKey = "com.urbanairship.content-extension-events"

...

// Create dictionary with custom event data
let customEventDict:[String:Any] = [customEventNameKey:"ConentExtensionEventName", customEventTimestampKey:NSNumber(value:Date.timeIntervalSinceReferenceDate)]
let groupDefaults = UserDefaults(suiteName: "group.com.yourdomain.yourapp") ?? UserDefaults.init(suiteName: "group.com.yourdomain.yourapp")

// Parse custom events array from user defaults
var customEventsArray = groupDefaults!.array(forKey: customEventsKey) ?? []
customEventsArray.append(customEventDict)

// Store custom events array in user defaults
groupDefaults!.set(customEventsArray, forKey: customEventsKey);

Retrieve Event Data and Send Custom Event

Inside your main application's AppDelegate, add the following method and call it within the didFinishLaunchingWithOptions callback:

// Retrieves custom event data from UserDefaults if one exists and sends it
func sendContentExtensionCustomEvents() {
    let customEventsKey = "com.urbanairship.content-extension-events"
    let customEventNameKey = "com.urbanairship.content-extension-event-name"
    let customEventTimestampKey = "com.urbanairship.content-extension-event-timestamp"

    let groupDefaults = UserDefaults(suiteName: "group.com.yourdomain.yourapp") ?? UserDefaults.init(suiteName: "group.com.yourdomain.yourapp")

    // Parse custom event dictionaries from user defaults
    if let customEvents = groupDefaults!.array(forKey: customEventsKey) {
        for customEventDict in customEvents {
            guard let normalized = customEventDict as? Dictionary<String, Any> else { continue }
            guard let customEventName = normalized[customEventNameKey] as? String else { continue }
            guard let customEventTimestamp = normalized[customEventTimestampKey] as? NSNumber else { continue }

            // Generate and add custom event to analytics
            UAirship.analytics()?.add(UACustomEvent(name: customEventName, value:customEventTimestamp))
        }
        // Overwrite custom events with empty array
        groupDefaults!.set([], forKey: customEventsKey);
    }
}

Debugging

Debugger feedback and console messages from the extension will not be forwarded to the debugging process of your application. To debug a content extension, you need to follow these steps:

  1. Run the Content Extension target:

  2. Select your application from the "Choose an app to run" menu:

Testing with Push

The easiest way to test your content extension is to send a push that includes the your category and mutable_content set to true inside the ios payload dictionary.

{
"audience":  {"tag":"<Your Audience>"},
"device_types" : ["ios"],
    "notification" : {
        "ios": {
        "category": "<Your Category>",
        "alert": "Content extension alert with custom event",
        "mutable_content": true
        }
    }
}
Tutorials