Display Interactive Notifications

Use interactive notifications to add buttons to push notifications from your mobile app. Marketing Cloud Engagement sends the category name for these interactive notifications in the message payload.

  1. Set up interactive notifications for your app using the sample code below. Adapt it to your specific requirements.

    The sample code applies to the AppDelegate.m didFinishLaunchingWithOptions application delegate method and shows how to create a category named Example. When you send this category with the payload from Marketing Cloud Engagement, the message appears in the notification center with buttons for user interaction.

  2. Examine the push notification’s payload in your push handler to check if your action triggered and your app performed the necessary response.

  3. After setup, work with an admin to enable interactive notifications on the MobilePush Administration page. The MobilePush Administration page in the Marketing Cloud Engagement UI, showing the Interactive Notifications option enabled.

Configure the SDK to create notification categories with custom actions. This code creates a category named Example with an action button. When Marketing Cloud Engagement sends a notification with this category, the notification displays with buttons that users can tap to trigger specific actions in your app.

1func configureSdk() -> Bool {
2
3  // Enable logging for debugging early on. Debug level is not recommended for
4  // production apps, because a large amount of data is logged to the console.
5
6  #if DEBUG
7    SFMCSdk.setLogger(logLevel: .debug)
8  #endif
9
10  // Use the `MarketingCloudSdkConfigBuilder` to configure the MarketingCloud
11  // SDK. This gives you the maximum flexibility in SDK configuration.
12  // The builder lets you configure the module parameters at runtime.
13
14  let engagementConfiguration = MarketingCloudSdkConfigBuilder(appId: appId)
15    .setAccessToken(accessToken)
16    .setMarketingCloudServerUrl(URL(string: appEndpoint)!)
17    .setMid(mid)
18    .setInboxEnabled(inbox)
19    .setLocationEnabled(location)
20    .setAnalyticsEnabled(pushAnalytics)
21    .build()
22
23  // Set the completion handler to take action when all modules initialization
24  // is completed. Setting the completion handler is optional.
25
26  let completionHandler: ((_ status: [ModuleInitStatus]) -> Void) = { [weak self] status in
27    DispatchQueue.main.async {
28      self?.handleSDKInitializationCompletion(status: status)
29    }
30  }
31
32  SFMCSdk.initializeSdk(
33    ConfigBuilder().setEngagement(config: engagementConfiguration).build(),
34    completion: completionHandler
35  )
36
37  return true
38}
39
40// MARK: - SDK Initialization Completion Handler
41
42private func handleSDKInitializationCompletion(status: [ModuleInitStatus]) {
43  var allSuccessful = true
44
45  for moduleStatus in status {
46    print("Module: \(moduleStatus.moduleName.rawValue), Status: \(moduleStatus.initStatus.rawValue)")
47
48    if moduleStatus.initStatus == .success {
49      // Handle successful initialization for each module
50      switch moduleStatus.moduleName {
51      case .engagement:
52        setupEngagement()
53      default:
54        break
55      }
56    } else if moduleStatus.initStatus == .error {
57      allSuccessful = false
58      // module failed to initialize, check logs for more details
59    } else if moduleStatus.initStatus == .cancelled {
60      allSuccessful = false
61      // module initialization was cancelled (for example due to
62      // re-configuration triggered before init was completed)
63    } else if moduleStatus.initStatus == .timeout {
64      allSuccessful = false
65      // module failed to initialize due to timeout, check logs for more details
66    }
67  }
68  if allSuccessful {
69    print("SDK initialization completed successfully")
70  } else {
71    print("SDK initialization completed with errors - check logs above")
72  }
73}
74
75func setupEngagement() {
76
77  // Get the LocationDelegate to a class adhering to the protocol.
78  // In this example, the AppDelegate class adheres to the protocol (see below)
79  // and handles URLs passed back from the SDK.
80  // For more information, see
81
82  MarketingCloudSdk.requestSdk { mc in
83      mc?.addTag("Hiking Supplies")
84  }
85
86  // Make sure to dispatch this to the main thread. UNUserNotificationCenter
87  // causes the app to show UI elements.
88  DispatchQueue.main.async {
89
90    // Set the delegate if needed, request authorization. If you use a
91    //delegate, set it here.
92    UNUserNotificationCenter.current().delegate = self
93
94    UNUserNotificationCenter.current().requestAuthorization(
95      options: [.alert, .sound, .badge],
96      completionHandler: {(_ granted: Bool, _ error: Error?) -> Void in
97      if error == nil {
98        (if granted == true {
99          // If app is authorized to use notifications, request a
100          //device token.
101          DispatchQueue.main.async {
102            UIApplication.shared.registerForRemoteNotifications()
103          }
104
105          // Support notification categories
106          let exampleAction = UNNotificationAction(
107            identifier: "App",
108            title: "Example",
109            options: []
110          )
111          let appCategory = UNNotificationCategory(
112            identifier: "Example",
113            actions: [exampleAction],
114            intentIdentifiers: [] as? [String] ?? [String](),
115            options: []
116          )
117          let categories = Set<AnyHashable>([appCategory])
118          UNUserNotificationCenter.current().setNotificationCategories(
119            categories as? Set<UNNotificationCategory> ?? Set<UNNotificationCategory>()
120          )
121        })
122      }
123    })
124  }
125}
126
127func application(
128  _ application: UIApplication,
129  didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
130  // Override point for customization after application launch.
131  self.configureSdk()
132  return true
133}
1func configureSdk() -> Bool {
2  #if DEBUG
3    SFMCSdk.setLogger(logLevel: .debug)
4  #endif
5
6  let mobilePushConfiguration = PushConfigBuilder(appId: appId)
7    .setAccessToken(accessToken)
8    .setMarketingCloudServerUrl(appEndpoint)
9    .setMid(mid)
10    .setInboxEnabled(inbox)
11    .setLocationEnabled(location)
12    .setAnalyticsEnabled(pushAnalytics)
13    .build()
14
15  let completionHandler: (OperationResult) -> () = { result in
16    if result == .success {
17      // This is a good place to set the contact key, tags, and attributes,
18      // because we know the SDK is ready.
19      self.setupMobilePush()
20    } else {
21      os_log("The SDK configuration failed. Current status: %@", result.rawValue)
22    }
23  }
24
25  SFMCSdk.initializeSdk(ConfigBuilder().setPush(config: mobilePushConfiguration, onCompletion: completionHandler).build())
26
27  return true
28}
29
30func setupMobilePush() {
31
32  SFMCSdk.identity.setProfileId("user@example.com")
33  SFMCSdk.identity.setProfileAttributes([["FavoriteTeamName": "favoriteTeamName"]])
34  SFMCSdk.requestPushSdk { mp in
35    mp.addTag("Hiking Supplies")
36  }
37
38  DispatchQueue.main.async {
39
40    // Set the delegate if needed. Then, ask if we're authorized - the delegate must be set here if used
41    UNUserNotificationCenter.current().delegate = self
42
43    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: {(_ granted: Bool, _ error: Error?) -> Void in
44      if error == nil {
45        if granted == true {
46          // we are authorized to use notifications, request a device token for remote notifications
47          DispatchQueue.main.async {
48            UIApplication.shared.registerForRemoteNotifications()
49          }
50
51          // Support notification categories
52          let exampleAction = UNNotificationAction(identifier: "App", title: "Example", options: [])
53          let appCategory = UNNotificationCategory(identifier: "Example", actions: [exampleAction], intentIdentifiers: [] as? [String] ?? [String](), options: [])
54          let categories = Set<AnyHashable>([appCategory])
55          UNUserNotificationCenter.current().setNotificationCategories(categories as? Set<UNNotificationCategory> ?? Set<UNNotificationCategory>())
56        }
57      }
58    })
59  }
60}
61
62// REQUIRED IMPLEMENTATION
63func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
64  return self.configureSdk()
65}
1func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
2
3    var error: NSError?
4    let success: Bool = MarketingCloudSDK.sharedInstance().sfmc_configure(&error)
5    if success == true {
6        // The SDK has been fully configured and is ready for use!
7
8        // Turn on logging for debugging.  Not recommended for production apps.
9        MarketingCloudSDK.sharedInstance().sfmc_setDebugLoggingEnabled(true)
10
11        // Great place for setting the contact key, tags and attributes since you know the SDK is setup and ready.
12        MarketingCloudSDK.sharedInstance().sfmc_setContactKey("user@example.com")
13        MarketingCloudSDK.sharedInstance().sfmc_addTag("Hiking Supplies")
14        MarketingCloudSDK.sharedInstance().sfmc_setAttributeNamed("FavoriteTeamName", value: "favoriteTeamName")
15
16        DispatchQueue.main.async {
17            if #available(iOS 10.0, *) {
18                // Set the delegate, if needed. Then, ask if we're authorized - the delegate must be set here if used
19                UNUserNotificationCenter.current().delegate = self
20                UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: {(_ granted: Bool, _ error: Error?) -> Void in
21                    if error == nil {
22                        if granted == true {
23                            // we are authorized to use notifications, request a device token for remote notifications
24                            DispatchQueue.main.async {
25                                UIApplication.shared.registerForRemoteNotifications()
26                            }
27
28                            // Support notification categories
29                            let exampleAction = UNNotificationAction(identifier: "App", title: "Example", options: [])
30                            let appCategory = UNNotificationCategory(identifier: "Example", actions: [exampleAction], intentIdentifiers: [] as? [String] ?? [String](), options: [])
31                            let categories = Set<AnyHashable>([appCategory])
32                            UNUserNotificationCenter.current().setNotificationCategories(categories as? Set<UNNotificationCategory> ?? Set<UNNotificationCategory>())
33                        }
34                    }
35                })
36            }
37            else {
38                let type: UIUserNotificationType = [UIUserNotificationType.badge, UIUserNotificationType.alert, UIUserNotificationType.sound]
39                let setting = UIUserNotificationSettings(types: type, categories: nil)
40                UIApplication.shared.registerUserNotificationSettings(setting)
41                UIApplication.shared.registerForRemoteNotifications()
42            }
43        }
44    }
45    else {
46        //  MarketingCloudSDK sfmc_configure failed
47        if #available(iOS 10.0, *) {
48            os_log("MarketingCloudSDK sfmc_configure failed with error = %@", error!)
49        } else {
50            // Fallback on earlier versions
51            NSLog("MarketingCloudSDK sfmc_configure failed with error = %@", error!)
52        }
53    }
54
55    return success
56}

Next, configure your app to respond when a user taps an action button. Implement the userNotificationCenter(_:didReceive:withCompletionHandler:) method to detect which action the user selected and respond accordingly. Check the actionIdentifier to determine which button the user tapped, then execute code that corresponds to that action.

1// The method is called on the delegate when the user responds to the
2// notification by opening the app, dismissing the notification, or choosing a
3// UNNotificationAction. Set the delegate before the app returns from
4// applicationDidFinishLaunching:.
5func userNotificationCenter(
6  _ center: UNUserNotificationCenter,
7  didReceive response: UNNotificationResponse,
8  withCompletionHandler completionHandler: @escaping () -> Void
9) {
10  // Tell the SDK about the notification
11  PushFeature.requestSdk { pushFeature in
12    pushFeature?.setNotificationResponse(response)
13  }
14  // Check your notification custom actions
15  if (response.actionIdentifier == "App") {
16    // Handle your notification’s custom action here
17  }
18}
1// The method is called on the delegate when the user responds to the
2// notification by opening the app, dismissing the notification, or choosing a
3// UNNotificationAction. Set the delegate before the app returns from
4// applicationDidFinishLaunching:.
5func userNotificationCenter(
6  _ center: UNUserNotificationCenter,
7  didReceive response: UNNotificationResponse,
8  withCompletionHandler completionHandler: @escaping () -> Void
9) {
10  // tell the SDK about the notification
11  SFMCSdk.requestPushSdk { mp in
12    mp.setNotificationRequest(response.notification.request)
13  }
14  // Check your notification custom actions
15  if (response.actionIdentifier == "App") {
16    // Handle your notification’s custom action here
17  }
18}
1// The method is called on the delegate when the user responds to the
2// notification by opening the app, dismissing the notification, or choosing a
3// UNNotificationAction. Set the delegate before the app returns from
4// applicationDidFinishLaunching:.
5func userNotificationCenter(
6  _ center: UNUserNotificationCenter,
7  didReceive response: UNNotificationResponse,
8  withCompletionHandler completionHandler: @escaping () -> Void
9) {
10  // tell the SDK about the notification
11  // See Step 5: Capture Notifications on Launch only for 8.0.x under Migrate to
12  // Mobile Push SDK Version 8.x for iOS to capture the notification request.
13  SFMCSdk.mp.setNotificationRequest(response.notification.request)
14
15  // Check your notification custom actions
16  if (response.actionIdentifier == "App") {
17    // Handle your notification’s custom action here
18  }
19}
1// The method is called on the delegate when the user responds to the
2// notification by opening the app, dismissing the notification, or choosing a
3// UNNotificationAction. Set the delegate before the app returns from
4// applicationDidFinishLaunching:.
5func userNotificationCenter(
6  _ center: UNUserNotificationCenter,
7  didReceive response: UNNotificationResponse,
8  withCompletionHandler completionHandler: @escaping () -> Void
9) {
10  // tell the MarketingCloudSDK about the notification
11  MarketingCloudSDK.sharedInstance().sfmc_setNotificationRequest(
12    response.notification.request
13  )
14  // Check your notification custom actions
15  if (response.actionIdentifier == "App") {
16    // Handle your notification’s custom action here
17  }
18}