Integrate the iOS SDK

You can integrate the Mobile App Messaging SDK into your iOS app to enable push notifications and user engagement features.

Prerequisites 

Add the Mobile App Messaging SDK dependencies to your project. There are three ways to add these dependencies:

Complete one of these processes before you continue.

Configure the SDK 

The configuration example in this section uses the MarketingCloudSDK ConfigBuilder configuration method. This method is the most flexible way to use the Mobile App Messaging SDK.

All method names contain the prefix sfmc_. Using this prefix helps avoid namespace collisions between the external libraries it uses. For more information, see Apple Developer Documentation: Customizing Existing Classes.

Configure the SDK in your application using mamAppID, mamAccessToken, mamServerURL, and mamTenantId.

1import MobileAppMessagingSDK
2import SFMCSDK
3
4class AppDelegate: UIResponder, UIApplicationDelegate {
5
6  var window: UIWindow?
7
8  // MobileAppMessaging Configuration
9  let mamAppID = "<your MAM appID here>"
10  let mamAccessToken = "<your MAM accessToken here>"
11  let mamServerURL = "<your MAM serverURL here>"
12  let mamTenantId = "<your MAM tenantId here>"
13  let mamAnalyticsEnabled = true
14
15  // MobilePush SDK: REQUIRED IMPLEMENTATION
16  @discardableResult
17
18  func configureSdk() -> Bool {
19
20    // Enable logging for debugging early on. Debug level is not recommended for production apps, as significant data
21    // about the SDK will be logged to the console.
22
23    #if DEBUG
24      SFMCSdk.setLogger(logLevel: .debug)
25    #endif
26
27    // Use the `MobileAppMessagingConfigBuilder` to configure the Mobile App Messaging SDK. This gives you the maximum flexibility in SDK configuration.
28    // The builder lets you configure the module parameters at runtime.
29
30    let mamConfiguration = MobileAppMessagingConfigBuilder(appId: mamAppID)
31      .setAccessToken(mamAccessToken)
32      .setMAMUrl(URL(string: mamServerURL)!)
33      .setTenantId(mamTenantId)
34      .setAnalyticsEnabled(mamAnalyticsEnabled)
35      .build()
36
37    // Set the completion handler to take action when all modules initialization is completed.
38    // Seting the completion handler is optional.
39
40    let completionHandler: ((_ status: [ModuleInitStatus]) -> Void) = { [weak self] status in
41      DispatchQueue.main.async {
42        self?.handleSDKInitializationCompletion(status: status)
43      }
44    }
45
46    SFMCSdk.initializeSdk(
47      ConfigBuilder().setMAM(config: mamConfiguration).build(), completion: completionHandler)
48
49    return true
50  }
51
52  // MARK: - SDK Initialization Completion Handler
53
54  private func handleSDKInitializationCompletion(status: [ModuleInitStatus]) {
55    var allSuccessful = true
56
57    for moduleStatus in status {
58      print(
59        "Module: \(moduleStatus.moduleName.rawValue), Status: \(moduleStatus.initStatus.rawValue)")
60
61      if moduleStatus.initStatus == .success {
62        // Handle successful initialization for each module
63        switch moduleStatus.moduleName {
64        case .mobileAppMessaging:
65          // Handle successful initialization for Mobile App Messaging module
66        default:
67          break
68        }
69      } else if moduleStatus.initStatus == .error {
70        allSuccessful = false
71        // module failed to initialize, check logs for more details
72      } else if moduleStatus.initStatus == .cancelled {
73        allSuccessful = false
74        // module initialization was cancelled (for example, if re-configuration
75        // was triggered before init completed)
76      } else if moduleStatus.initStatus == .timeout {
77        allSuccessful = false
78        // module failed to initialize due to timeout, check logs for more details
79      }
80    }
81    if allSuccessful {
82      print("SDK initialization completed successfully")
83    } else {
84      print("SDK initialization completed with errors - check logs above")
85    }
86  }
87
88  // MobilePush SDK: REQUIRED IMPLEMENTATION
89  func application(
90    _ application: UIApplication,
91    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
92  ) -> Bool {
93    self.configureSdk()
94    return true
95  }
96
97  // MobilePush SDK: OPTIONAL IMPLEMENTATION (if using Data Protection)
98  func applicationProtectedDataDidBecomeAvailable(_ application: UIApplication) {
99    self.configureSdk()
100  }
101}

iOS Data Protection affects the SDK as described in this table.

iOS Data Protection LevelSDK Behavior
No protectionSDK works in the foreground and background.
Complete until first user authenticationSDK works in the foreground and background after first unlock.
Complete unless openSDK works in the foreground and background after first unlock.
CompleteSDK works only in the foreground after the device is unlocked.

Enable Push Notifications 

Before you enable push notifications, provision your app for push notifications.

  1. Enable push notifications in your target’s Capabilities settings.

  2. Set your AppDelegate class to adhere to the UIApplicationDelegate and UNUserNotificationCenterDelegate protocol.

    1class AppDelegate: UIApplicationDelegate, UNUserNotificationCenterDelegate
    2...
  3. Extend the SDK configuration code outlined in Configure the SDK to add support for push registration.

    1// Mobile APP Messaging SDK: REQUIRED IMPLEMENTATION
    2 func configureSdk() -> Bool {
    3
    4   // Enable logging for debugging early on. Debug level is not recommended for production apps, as significant data
    5   // about the SDK will be logged to the console.
    6   #if DEBUG
    7     SFMCSdk.setLogger(logLevel: .debug)
    8   #endif
    9
    10   // Use the `PushFeatureConfigBuilder` to configure the Push Feature SDK. This gives you the maximum flexibility in SDK configuration.
    11   // The builder lets you configure the module parameters at runtime.
    12
    13   let pushFeatureConfiguration = PushFeatureConfigBuilder()
    14     .setApplicationControlsBadging(true)
    15     .build()
    16
    17   // Set the completion handler to take action when all modules initialization is completed.
    18   // Seting the completion handler is optional.
    19
    20   let completionHandler: ((_ status: [ModuleInitStatus]) -> Void) = { [weak self] status in
    21     DispatchQueue.main.async {
    22       self?.handleSDKInitializationCompletion(status: status)
    23     }
    24   }
    25
    26   SFMCSdk.initializeSdk(ConfigBuilder().setMAM(
    27     config: pushFeatureConfiguration).build(),
    28     completion: completionHandler
    29   )
    30
    31   return true
    32 }
    33
    34 // MARK: - SDK Initialization Completion Handler
    35
    36 private func handleSDKInitializationCompletion(status: [ModuleInitStatus]) {
    37   var allSuccessful = true
    38
    39   for moduleStatus in status {
    40     print("Module: \(moduleStatus.moduleName.rawValue), Status: \(moduleStatus.initStatus.rawValue)")
    41
    42     if moduleStatus.initStatus == .success {
    43       // Handle successful initialization for each module
    44       switch moduleStatus.moduleName {
    45       case .pushFeature:
    46         setupPushFeature()
    47       default:
    48         break
    49       }
    50     } else if moduleStatus.initStatus == .error {
    51       allSuccessful = false
    52       // module failed to initialize, check logs for more details
    53     } else if moduleStatus.initStatus == .cancelled {
    54       allSuccessful = false
    55       // module initialization was cancelled (for example if the
    56       // re-configuration was triggered before initialization completed)
    57     } else if moduleStatus.initStatus == .timeout {
    58       allSuccessful = false
    59       // module failed to initialize due to timeout, check logs for more details
    60     }
    61   }
    62   if allSuccessful {
    63     print("SDK initialization completed successfully")
    64   } else {
    65     print("SDK initialization completed with errors - check logs above")
    66   }
    67 }
    68
    69 func setupPushFeature() {
    70   // Set the URLHandlingDelegate to handle URLs from CloudPage, OpenDirect,
    71   //Location, and Inbox messages. In this example, the AppDelegate class adheres
    72   // to the URLHandlingDelegate protocol (see below).
    73   PushFeature.requestSdk { pushFeature in
    74     DispatchQueue.main.async {
    75       pushFeature?.setURLHandlingDelegate(self)
    76     }
    77   }
    78 }
    79
    80 func application(
    81   _ application: UIApplication,
    82   didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    83 ) -> Bool {
    84   self.configureSdk()
    85   return true
    86 }
  4. Add the required UIApplicationDelegate protocol methods to support push registration to your AppDelegate class.

    1// PushFeature SDK: REQUIRED IMPLEMENTATION
    2 func application(
    3   _ application: UIApplication,
    4   didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    5 ) {
    6   // Save the device token
    7   PushFeature.requestSdk { pushFeature in
    8       pushFeature?.setDeviceToken(deviceToken)
    9   }
    10 }
    11
    12 // Mobile App Messaging SDK: REQUIRED IMPLEMENTATION
    13 func application(
    14   _ application: UIApplication,
    15   didFailToRegisterForRemoteNotificationsWithError error: Error
    16 ) {
    17   // Log the error
    18   print(error)
    19 }
    20
    21 // PushFeature SDK: REQUIRED IMPLEMENTATION
    22 /**
    23 This delegate method lets apps with the "remote-notification" background mode
    24 fetch data in response to an incoming remote notification.
    25
    26 Call the fetchCompletionHandler as soon as you're finished performing that
    27 operation so the system can accurately estimate its power and data cost.
    28
    29 This method is invoked even if the application was launched or resumed because
    30 of the remote notification. The delegate methods are invoked first.
    31
    32 This behavior is in contrast to `application(_:didReceiveRemoteNotification:)`,
    33 which isn't called in those cases, and isn't invoked if this method is implemented.
    34 **/
    35 func application(
    36   _ application: UIApplication,
    37   didReceiveRemoteNotification userInfo: [AnyHashable: Any],
    38   fetchCompletionHandler completionHandler: @escaping (
    39     UIBackgroundFetchResult
    40   ) -> Void
    41 ) {
    42   PushFeature.requestSdk { pushFeature in
    43     pushFeature?.setNotificationUserInfo(userInfo)
    44   }
    45
    46   completionHandler(.newData)
    47 }
  5. Add the required UNUserNotificationCenterDelegate protocol methods to support push notifications to your AppDelegate class.

    1/**
    2 The method is called on the delegate when the user responds to the notification
    3 by opening the application, dismissing the notification or choosing a
    4 UNNotificationAction. The delegate must be set before the application returns
    5 from applicationDidFinishLaunching:.
    6 **/
    7 func userNotificationCenter(
    8   _ center: UNUserNotificationCenter,
    9   didReceive response: UNNotificationResponse,
    10   withCompletionHandler completionHandler: @escaping () -> Void
    11 ) {
    12   // Required: Tell theSDK about the notification so that it begins to
    13   // collect analytics and process the notification for your app.
    14   PushFeature.requestSdk { pushFeature in
    15     pushFeature?.setNotificationResponse(response)
    16   }
    17   completionHandler()
    18 }
    19
    20 /**
    21 The method is called on the delegate only if the application is in the
    22 foreground. If the method isn't implemented or the handler isn't called in a
    23 timely manner, then the notification isn't shown. The application can
    24 have the notification presented as a sound, badge, alert, or it can appear
    25 in the notification list. This decision should be based on whether the
    26 information in the notification is otherwise visible to the user.
    27 **/
    28 func userNotificationCenter(
    29   _ center: UNUserNotificationCenter,
    30   willPresent notification: UNNotification,
    31   withCompletionHandler completionHandler: @escaping (
    32     UNNotificationPresentationOptions
    33   ) -> Void
    34 ) {
    35   completionHandler(.alert)
    36 }