Customize Push Notification Functionality for iOS Apps

Extend push notification support in your mobile app beyond the built-in functionality of basic configuration with the following customization options.

Custom Sound

Play a custom sound when a push notification arrives.

Interactive Notifications

Display buttons on your push notifications.

Rich Notifications

Include photos and videos.

Custom Keys

Send extra data along with a push notification. For example, add tracking to your mobile app.

URL Handling

Handle URLs from push notifications

Specify a Custom Notification Sound 

This feature uses a sound included in your mobile app as a custom audio signal when a push message arrives on the mobile device.

  1. Add a file named custom.caf to your project. The cloud push payload looks for a file named custom.caf. The project file explorer in Xcode, showing a file named custom.caf.
  2. Add the custom.caf audio file to the Copy Bundle Resources folder in Xcode for your app. The Build Phases tab in Xcode, showing the Copy Bundle Resources phase with the custom.caf file selected.
  3. To prevent Xcode from using cached files, perform a clean build folder in Xcode. In the Product menu, hold the Option key and select Clean Build Folder.
  4. Enable the custom sound option on the MobilePush Administration page. You might need to work with a Marketing Cloud Engagement admin to enable this option. The MobilePush Administration page in the Marketing Cloud Engagement UI, showing the Custom Sound option enabled.

Display Interactive Notifications 

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

  1. To set up interactive notifications for your app, use the sample code in the Example Implementation section as a reference and adapt it to your specific requirements.

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

    Note

  2. To check if your action triggered and your app performed the necessary response, examine the push notification’s payload in your push handler. Use the sample code in the Example: Handle Actions section as a reference and adapt it to your specific requirements.

  3. After setup, ask your Engagement 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.

Example Implementation 

This code example shows how to customize push notifications for iOS apps that use SDK version 10 and later.

SDK for iOS, version 10
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}

For version 8 of the SDK, use this code.

8.x
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// MobilePush SDK: REQUIRED IMPLEMENTATION
63func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
64  return self.configureSdk()
65}

For version 7 of the SDK, use this code.

7.x
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}

Example: Handle Actions 

In your push handler, examine the push notification’s payload to see if your action is triggered and if your application performed the action.

This code example shows how to handle actions using version 10 of the SDK.

SDK for iOS, version 10
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}

For version 8.1 of the SDK, use this code.

SDK for iOS, version 8.1
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}

For version 8.0 of the SDK, use this code.

SDK for iOS, version 8.0
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}

For version 7 of the SDK, use this code.

SDK for iOS, version 7
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}

Send Rich Notifications 

Rich notifications include images, videos, titles, and subtitles from the MobilePush app and mutable content. Mutable content can include personalization in the title, subtitle, or body of your message.

Prerequisites 

  • Make sure that your app is built for iOS version 10 .
  • Include a service extension for your app that can handle mutable content. For information on adding a service app extension, see Modifying and Presenting Notifications.
  • Make sure that your app is registered for push notifications via the MobilePush SDK.

Create a Notification Service Extension 

Skip these steps if you've already integrated Notification Service Extension during the MobilePush Extension SDK integration.

  1. Click File > New > Target.
  2. Select Notification Service Extension.
  3. Name and save the new extension.
  4. In your project target’s General settings, confirm that the new extension is listed in the Frameworks, Libraries, and Embedded Content section. If not, add it.

The Notification Target must be signed with the same Xcode Managed Profile as the main project.

Important

This service extension checks for a _mediaUrl element in request.content.userInfo. If found, the extension attempts to download the media from the URL, creates a thumbnail-size version, and then adds the attachment. The service extension also checks for a _mediaAlt element in request.content.userInfo. If found, the service extension uses the element for the body text if there are any problems downloading or creating the media attachment.

A service extension can timeout if it’s unable to download. In this code sample, the service extension delivers the original content with the body text changed to the value in _mediaAlt.

Without Extension SDK Integration
1import UserNotifications
2import CoreGraphics
3
4class MyNotificationService: UNNotificationServiceExtension {
5
6    var contentHandler: ((UNNotificationContent) -> Void)?
7    var bestAttemptContent: UNMutableNotificationContent?
8
9    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
10        self.contentHandler = contentHandler
11        self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
12
13        self.addMedia(request) {
14            self.contentHandler!(self.bestAttemptContent!)
15        }
16    }
17
18    override func serviceExtensionTimeWillExpire() {
19        // Called just before the extension is terminated by the system.
20        // Use this as an opportunity to deliver your "best attempt" at modified content. Otherwise, the original push payload will be used.
21        // We took too long to download the media URL. Use the alternate text if provided.
22        self.useAltText()
23
24        // Tell the OS that the process is complete and the content is ready to be presented.
25        self.contentHandler!(self.bestAttemptContent!)
26    }
27
28    private func useAltText() {
29        if let mediaAltText = self.bestAttemptContent?.userInfo["_mediaAlt"] as? String {
30            // alternative text to display if there are any issues loading the media URL
31            if mediaAltText.isEmpty == false {
32                self.bestAttemptContent?.body = mediaAltText
33            }
34        }
35    }
36
37    private func addMedia(_ request: UNNotificationRequest, completion: @escaping () -> Void) {
38        guard let mediaUrlString = request.content.userInfo["_mediaUrl"] as? String,
39                !mediaUrlString.isEmpty  else {
40            useAltText()
41            completion()
42            return
43        }
44
45        guard let mediaUrl = URL(string: mediaUrlString) else {
46            useAltText()
47            completion()
48            return
49        }
50
51        let session = URLSession(configuration: URLSessionConfiguration.default)
52        let downloadTask = session.downloadTask(with: mediaUrl) { [weak self]
53            location, response, error in
54            if let _ = error {
55                self?.useAltText()
56                completion()
57                return
58            }
59
60            guard let theLocation = location else {
61                self?.useAltText()
62                completion()
63                return
64            }
65
66            guard let theResponse = response as? HTTPURLResponse else {
67                self?.useAltText()
68                completion()
69                return
70            }
71
72            let statusCode = theResponse.statusCode
73            guard (statusCode >= 200 && statusCode <= 299) else {
74                self?.useAltText()
75                completion()
76                return
77            }
78
79            let localMediaUrl = URL.init(fileURLWithPath: theLocation.path + mediaUrl.lastPathComponent)
80
81            // Remove any existing file with the same name
82            try? FileManager.default.removeItem(at: localMediaUrl)
83
84            do {
85                try FileManager.default.moveItem(at: theLocation, to: localMediaUrl)
86            } catch {
87                self?.useAltText()
88                completion()
89                return
90            }
91
92            guard let mediaAttachment = try? UNNotificationAttachment(identifier: "SomeAttachmentId",
93                                                                      url: localMediaUrl) else {
94                self?.useAltText()
95                completion()
96                return;
97            }
98
99            guard let theContent = self?.bestAttemptContent else {
100                self?.useAltText()
101                completion()
102                return
103            }
104
105            theContent.attachments = [mediaAttachment]
106            completion()
107        }
108
109        downloadTask.resume()
110    }
111}
With Extension SDK Integration
1//
2//  NotificationService.swift
3//  MyServiceExtension
4//
5//
6
7import UserNotifications
8import MCExtensionSDK
9
10class NotificationService: SFMCNotificationService {
11
12    // Use this method to enable logging, change logging levels, etc. , if required.
13    override func sfmcProvideConfig() -> SFNotificationServiceConfig {
14        var logLevel: LogLevel = .none
15#if DEBUG
16        logLevel = .debug
17#endif
18        return SFNotificationServiceConfig(logLevel: logLevel)
19    }
20
21    // Use this method only if you need to perform any custom processing for images, video downloads, inserting custom keys in notification userInfo, and so on.
22    // Don’t modify  `mutableContent.request.content.userInfo` directly. Doing so may trigger an exception.
23    // To add any custom key in notification userInfo, return a dictionary in the completion handler.
24
25
26    // Like the `UNNotificationServiceExtension` method - func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) → Void), you'll only have limited time from the system for processing.
27    override func sfmcDidReceive(_ request: UNNotificationRequest, mutableContent: UNMutableNotificationContent, withContentHandler contentHandler: @escaping ([AnyHashable : Any]?) -> Void) {
28        // Your custom code here
29        //...
30        self.addMedia(mutableContent) {
31            // To add any custom key:value pair(s) in notifications userInfo object, then
32            var customUserInfo: [AnyHashable : Any] = [:]
33            customUserInfo["MyCustomKey"] = "MyCustomValue"
34
35            // Finally, call the content handler to signal the end of your processing operation.
36            //
37            contentHandler(customUserInfo)
38        }
39    }
40
41    private func addMedia(_ mutableContent: UNMutableNotificationContent, completion: @escaping () -> Void) {
42        guard let mediaUrlString = mutableContent.userInfo["_mediaUrl"] as? String,
43                !mediaUrlString.isEmpty  else {
44            completion()
45            return
46        }
47
48        guard let mediaUrl = URL(string: mediaUrlString) else {
49            completion()
50            return
51        }
52
53        let session = URLSession(configuration: URLSessionConfiguration.default)
54        let downloadTask = session.downloadTask(with: mediaUrl) { [weak self]
55            location, response, error in
56            if let _ = error {
57                completion()
58                return
59            }
60
61            guard let theLocation = location else {
62                completion()
63                return
64            }
65
66            guard let theResponse = response as? HTTPURLResponse else {
67                completion()
68                return
69            }
70
71            let statusCode = theResponse.statusCode
72            guard (statusCode >= 200 && statusCode <= 299) else {
73                completion()
74                return
75            }
76
77            let localMediaUrl = URL.init(fileURLWithPath: theLocation.path + mediaUrl.lastPathComponent)
78
79            // Remove any existing file with the same name
80            try? FileManager.default.removeItem(at: localMediaUrl)
81
82            do {
83                try FileManager.default.moveItem(at: theLocation, to: localMediaUrl)
84            } catch {
85                completion()
86                return
87            }
88
89            guard let mediaAttachment = try? UNNotificationAttachment(identifier: "SomeAttachmentId",
90                                                                      url: localMediaUrl) else {
91                completion()
92                return;
93            }
94
95            mutableContent.attachments = [mediaAttachment]
96            completion()
97        }
98
99        downloadTask.resume()
100    }
101}

Handle Custom Keys Sent with Message Payload 

Use custom keys to send extra data along with a push notification. You can use custom keys to add tracking or additional functionality to your app. For example, you can define a custom key that allows a third-party application to provide custom tracking information regarding customer usage on your mobile app. This data can include an ID value used by the app to retrieve additional data or other function.

You must enable this feature in the Administration page on the Engagement UI.

Note

The MobilePush Administration page in Marketing Cloud Engagement, showing the Custom Keys option enabled.

To implement custom key support in your app, extend your push notification handler to extract the push’s userInfo dictionary and the values contained in it.

This code example shows how to handle custom keys using version 10 of the SDK.

SDK for iOS, version 10
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 application 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  // the dictionary containing custom keys
15  let userInfo = response.notification.request.content.userInfo
16  let someValue = userInfo["someKey"] as? String
17  // App-specific usage
18  print(someValue ?? "someValue is nil")
19  completionHandler()
20}

For version 9 of the SDK, use this code.

SDK for iOS, version 9
1// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from applicationDidFinishLaunching:.
2func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
3    // tell the SDK about the notification
4    SFMCSdk.requestPushSdk { mp in
5        mp.setNotificationResponse(response)
6    }
7    // the dictionary containing custom keys
8    let userInfo = response.notification.request.content.userInfo
9    let someValue = userInfo["someKey"] as? String
10    // application-specific usage follows
11    print(someValue ?? "someValue is nil")
12    completionHandler()
13}

For version 8.1 of the SDK, use this code.

SDK for iOS, version 8.1
1// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from applicationDidFinishLaunching:.
2func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
3    // tell the SDK about the notification
4    SFMCSdk.requestPushSdk { mp in
5        mp.setNotificationRequest(response.notification.request)
6    }
7    // the dictionary containing custom keys
8    let userInfo = response.notification.request.content.userInfo
9    let someValue = userInfo["someKey"] as? String
10    // application-specific usage follows
11    print(someValue ?? "someValue is nil")
12    completionHandler()
13}

For version 8.0 of the SDK, use this code.

SDK for iOS, version 8.0
1// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from applicationDidFinishLaunching:.
2func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
3    // Tell the SDK about the notification
4    // See Step 5: Capture Notifications on Launch only for 8.0.x under Migrate to Mobile Push SDK Version 8.x for iOS to capture the notification request.
5    mp.setNotificationRequest(response.notification.request)
6
7    // the dictionary containing custom keys
8    let userInfo = response.notification.request.content.userInfo
9    let someValue = userInfo["someKey"] as? String
10    // application-specific usage follows
11    print(someValue ?? "someValue is nil")
12    completionHandler()
13}

For version 7 of the SDK, use this code.

SDK for iOS, version 7
1// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from applicationDidFinishLaunching:.
2func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
3    // tell the MarketingCloudSDK about the notification
4    MarketingCloudSDK.sharedInstance().sfmc_setNotificationRequest(response.notification.request)
5    // the dictionary containing custom keys
6    let userInfo = response.notification.request.content.userInfo
7    let someValue = userInfo["someKey"] as? String
8    // application-specific usage follows
9    print(someValue ?? "someValue is nil")
10    completionHandler()
11}

Messages with an OpenDirect URL 

OpenDirect customized push messages contain a URL in the payload. The MobilePush SDK can pass this URL to your application to handle. For information about handling URLs from push notifications that use OpenDirect, see Handle URLs.

A marketing admin can enable OpenDirect on the MobilePush Administration page in Marketing Cloud Engagement.

The MobilePush Administration page in Marketing Cloud Engagement, showing the Open Direct option enabled.

Handle URLs 

The SDK doesn’t automatically present URLs from these sources:

  • CloudPages URLs from push notifications
  • OpenDirect URLs from push notifications
  • CloudPages URLs from inbox messages using the built-in UITableView delegate

To handle URLs from these sources, follow these steps.

  1. Implement the URLHandlingDelegate (v8.x) or MarketingCloudSDKURLHandlingDelegate (v7.x) protocol in your app.
  2. Use setURLHandlingDelegate (v8.x) or sfmc_setURLHandlingDelegate: method to set a delegate for the protocol.
  3. Next, you’re prompted to implement the protocol method sfmc_handleURL:type:

When an OpenDirect or CloudPages push notification is received, the SDK passes a NSURL value to sfmc_handleURL:type:. This value contains the push notification or inbox message, and includes the URL. A type value also reflects the source of the URL, which is either SFMCURLTypeCloudPages or SFMCURLTypeOpenDirect.

If the development language is Swift, the class that implements the URLHandlingDelegate (in version 8 or later) or MarketingCloudSDKURLHandlingDelegate (in version 7) delegate must be Objective-C compatible. This means that you must prefix the class with @objc and extend NSObject, as shown in this example.

Important

Example 

This code example shows how to handle URLs using version 10 of the SDK.

SDK for iOS, version 10
1// Framework import
2import SFMCSDK
3import MarketingCloudSDK
4import PushFeatureSDK
5
6// Make sure your class adopts the protocol
7@objc class MyClass: NSObject, URLHandlingDelegate
8
9...
10// Set the delegate somewhere in your application code after configuring the SDK
11  PushFeature.requestSdk { pushFeature in
12    pushFeature?.setURLHandlingDelegate(self)
13  }
14...
15
16// EXAMPLE IMPLEMENTATIONS
17// Implement the protocol method and have iOS handle the URL itself
18func sfmc_handleURL(_ url: URL, type: String) {
19  if UIApplication.shared.canOpenURL(url) == true {
20    if #available(iOS 10.0, *) {
21      UIApplication.shared.open(url, options: [:], completionHandler: { success in
22        if success {
23          print("url \(url) opened successfully")
24        } else {
25          print("url \(url) could not be opened")
26        }
27      })
28    } else {
29      if UIApplication.shared.openURL(url) == true {
30        print("URL \(url) opened successfully")
31      } else {
32        print("Couldn't open URL \(url)")
33      }
34    }
35  }
36}
37
38// Implement the protocol method and use SFSafariViewController to present the
39// URL within your app
40func sfmc_handleURL(_ url: URL, type: String) {
41  let safariViewController = SFSafariViewController(url: url)
42  window?.topViewController()?.present(safariViewController, animated: true) {}
43}
44
45// Implement the protocol method and take app-specific actions based on the URL
46func sfmc_handleURL(_ url: URL, type: String) {
47  let queryItems = URLComponents(string: url.absoluteString)?.queryItems
48  for item: URLQueryItem? in queryItems ?? [] {
49    // do something in your application based on the parameters in the URL
50  }
51}

For version 8.1 of the SDK, use this code.

SDK for iOS, version 8.1
1// Framework import
2import SFMCSDK
3import MarketingCloudSDK
4
5// Make sure your class adopts the protocol
6@objc class MyClass: NSObject, URLHandlingDelegate
7
8...
9// Set the delegate somewhere in your application code after configuring the SDK
10SFMCSdk.requestPushSdk { mp in
11    mp.setURLHandlingDelegate(self)
12}
13...
14
15// EXAMPLE IMPLEMENTATIONS
16// Implement the protocol method and have iOS handle the URL itself
17func sfmc_handleURL(_ url: URL, type: String) {
18  if UIApplication.shared.canOpenURL(url) == true {
19    if #available(iOS 10.0, *) {
20      UIApplication.shared.open(url, options: [:], completionHandler: { success in
21        if success {
22          print("url \(url) opened successfully")
23        } else {
24          print("url \(url) could not be opened")
25        }
26      })
27    } else {
28      if UIApplication.shared.openURL(url) == true {
29        print("url \(url) opened successfully")
30      } else {
31        print("url \(url) could not be opened")
32      }
33    }
34  }
35}
36
37// Implement the protocol method and use SFSafariViewController to present the
38// URL within your app
39func sfmc_handleURL(_ url: URL, type: String) {
40    let safariViewController = SFSafariViewController(url: url)
41    window?.topViewController()?.present(safariViewController, animated: true) {
42    }
43}
44
45// Implement the protocol method and take app-specific actions based on the URL
46func sfmc_handleURL(_ url: URL, type: String) {
47    let queryItems = URLComponents(string: url.absoluteString)?.queryItems
48    for item: URLQueryItem? in queryItems ?? [] {
49        // do something interesting in your application based on the pararmeters in the URL
50    }
51}

For version 8.0 of the SDK, use this code.

SDK for iOS, version 8.0
1// Framework import
2import SFMCSDK
3import MarketingCloudSDK
4
5// Make sure your class adopts the protocol
6@objc class MyClass: NSObject, URLHandlingDelegate
7
8...
9// Set the delegate somewhere in your application code after configuring the SDK
10// and confirming that the SDK is operational
11    mp.setURLHandlingDelegate(self)
12...
13// EXAMPLE IMPLEMENTATIONS
14// Implement the protocol method and have iOS handle the URL itself
15func sfmc_handleURL(_ url: URL, type: String) {
16  if UIApplication.shared.canOpenURL(url) == true {
17    if #available(iOS 10.0, *) {
18      UIApplication.shared.open(url, options: [:], completionHandler: { success in
19          if success {
20            print("url \(url) opened successfully")
21          } else {
22            print("url \(url) could not be opened")
23          }
24      })
25    } else {
26      if UIApplication.shared.openURL(url) == true {
27        print("url \(url) opened successfully")
28      } else {
29        print("url \(url) could not be opened")
30      }
31    }
32  }
33}
34
35// Implement the protocol method and use SFSafariViewController to present the
36// URL within your app
37func sfmc_handleURL(_ url: URL, type: String) {
38  let safariViewController = SFSafariViewController(url: url)
39  window?.topViewController()?.present(safariViewController, animated: true) {
40  }
41}
42
43// Implement the protocol method and take app-specific actions based on the URL
44func sfmc_handleURL(_ url: URL, type: String) {
45  let queryItems = URLComponents(string: url.absoluteString)?.queryItems
46  for item: URLQueryItem? in queryItems ?? [] {
47    // do something in the app based on the parameters in the URL
48  }
49}

For version 7 of the SDK, use this code.

SDK for iOS, version 7
1// Framework import
2import MarketingCloudSDK
3
4// Make sure your class adopts the protocol
5@objc class MyClass: NSObject, MarketingCloudSDKURLHandlingDelegate
6
7...
8// Set the delegate somewhere in your application code after configuring the SDK
9MarketingCloudSDK.sharedInstance().sfmc_setURLHandlingDelegate(self)
10...
11// EXAMPLE IMPLEMENTATIONS
12// Implement the protocol method and have iOS handle the URL itself
13func sfmc_handleURL(_ url: URL, type: String) {
14  if UIApplication.shared.canOpenURL(url) == true {
15    if #available(iOS 10.0, *) {
16      UIApplication.shared.open(url, options: [:], completionHandler: { success in
17        if success {
18          print("url \(url) opened successfully")
19        } else {
20          print("url \(url) could not be opened")
21        }
22      })
23    } else {
24      if UIApplication.shared.openURL(url) == true {
25        print("url \(url) opened successfully")
26      } else {
27        print("url \(url) could not be opened")
28      }
29    }
30  }
31}
32
33// Implement the protocol method and use SFSafariViewController to present the
34// URL within your app
35func sfmc_handleURL(_ url: URL, type: String) {
36  let safariViewController = SFSafariViewController(url: url)
37  window?.topViewController()?.present(safariViewController, animated: true) {
38  }
39}
40
41// Implement the protocol method and take app-specific actions based on the URL
42func sfmc_handleURL(_ url: URL, type: String) {
43  let queryItems = URLComponents(string: url.absoluteString)?.queryItems
44  for item: URLQueryItem? in queryItems ?? [] {
45    // do something in the app based on the parameters in the URL
46  }
47}

Push Delivery Analytics 

Starting with version 9.0.0, the MobilePush iOS SDK tracks successful delivery of push notifications to the SDK. To enable this feature, contact your Engagement admin.

For more information, see MobilePush Install, Inactive Devices, Push Delivery Events