Configure the MobilePush SDK Flutter Plugin for iOS Apps

After you install and configure the MobilePush SDK Flutter plugin, configure the plugin to enable push support for the iOS platform.

Prerequisites 

Before you configure the MobilePush SDK Flutter plugin for iOS apps, make sure that the plugin is installed and configured for your app. See Marketing Cloud Flutter Plugin.

Enable Push Notifications 

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

Enable Push

Update the AppDelegate 

  1. Navigate to the YOUR_APP/ios directory and open Runner.xcworkspace.

  2. To configure the SDK and enable push, update AppDelegate.

Swift
1//AppDelegate.swift
2
3
4import UIKit
5import Flutter
6import SFMCSDK
7import MarketingCloudSDK
8
9       func setupMobilePush() {
10           // Make sure to dispatch this to the main thread, as UNUserNotificationCenter will present UI.
11           DispatchQueue.main.async {
12               // Set the UNUserNotificationCenterDelegate to a class adhering to thie protocol.
13               // In this exmple, the AppDelegate class adheres to the protocol (see below)
14               // and handles Notification Center delegate methods from iOS.
15               UNUserNotificationCenter.current().delegate = self
16
17               // Request authorization from the user for push notification alerts.
18               UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: {(_ granted: Bool, _ error: Error?) -> Void in
19                   if error == nil {
20                       if granted == true {
21                           // Your application may want to do something specific if the user has granted authorization
22                           // for the notification types specified; it would be done here.
23                       }
24                   }
25               })
26
27               // Your application should register for remote notifications each time your application
28               // launches to make sure that the push token for silent push is updated, if necessary.
29
30               // Registering in this manner doesn't mean that a user sees a notification. It only means
31               // that the application receives a unique push token from iOS.
32               UIApplication.shared.registerForRemoteNotifications()
33           }
34       }
35
36@UIApplicationMain
37@objc class AppDelegate: FlutterAppDelegate {
38
39
40    // The appID, accessToken and appEndpoint are required values for MobilePush SDK Module configuration and are obtained from your app.
41    // See https://salesforce-marketingcloud.github.io/MarketingCloudSDK-iOS/get-started/get-started-setupapps.html for more information.
42    let appID = "<your appID>"
43    let accessToken = "<your accessToken>"
44    let appEndpointURL = "<your appEndpoint>"
45    let mid = "<your account MID>"
46    // Define features your app uses.
47    let analytics = true
48
49
50    override func application(
51        _ application: UIApplication,
52        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
53    ) -> Bool {
54        GeneratedPluginRegistrant.register(with: self)
55
56
57           // Required: tell the MarketingCloudSDK about the notification. The SDK collects analytics
58           // and processes the notification on behalf of your application.
59           SFMCSdk.requestPushSdk { mp in
60               mp.setNotificationResponse(response)
61           }
62
63
64        // rest of the didFinishLaunchingWithOptions method...
65        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
66    }
67
68           completionHandler(.alert)
69       }
70
71}
Objective-C
1//AppDelegate.h
2
3#import <Flutter/Flutter.h>
4#import <UIKit/UIKit.h>
5#import <UserNotifications/UserNotifications.h>
6#import <SFMCSDK/SFMCSDK.h>
7//Other imports...
8
9@interface AppDelegate : FlutterAppDelegate<UNUserNotificationCenterDelegate>
10
11@end
12
13//AppDelegate.m
14
15#import "AppDelegate.h"
16#import "GeneratedPluginRegistrant.h"
17#import <MarketingCloudSDK/MarketingCloudSDK.h>
18//Other imports...
19
20@implementation AppDelegate
21
22- (BOOL)application:(UIApplication *)application
23    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
24
25    //Flutter setup
26    [GeneratedPluginRegistrant registerWithRegistry:self];
27    // Override point for customization after application launch.
28
29    // Use the Push Config Builder to configure the Mobile Push Module. This gives you the maximum flexibility in SDK configuration.
30    // The builder lets you configure the module parameters at runtime.
31    PushConfigBuilder *pushConfigBuilder = [[PushConfigBuilder alloc] initWithAppId:@"{MC_APP_ID}"];
32    [pushConfigBuilder setAccessToken:@"{MC_ACCESS_TOKEN}"];
33    [pushConfigBuilder setMarketingCloudServerUrl:[NSURL URLWithString:@"{MC_APP_SERVER_URL}"]];
34    [pushConfigBuilder setMid:@"MC_MID"];
35    [pushConfigBuilder setAnalyticsEnabled:YES];
36
37
38    // Once you've created the mobile push configuration, intialize the SDK.
39    [SFMCSdk initializeSdk:[[[SFMCSdkConfigBuilder new] setPushWithConfig:[pushConfigBuilder build] onCompletion:^(SFMCSdkOperationResult result) {
40        if (result == SFMCSdkOperationResultSuccess) {
41            // module is fully configured and ready for use
42            [self pushSetup];
43        } else {
44            NSLog(@"SFMC sdk configuration failed.");
45        }
46    }] build]];
47
48    // rest of the didFinishLaunchingWithOptions method...
49    return [super application:application didFinishLaunchingWithOptions:launchOptions];
50}
51
52- (void)pushSetup {
53    // Make sure to dispatch this to the main thread, as UNUserNotificationCenter will present UI.
54    dispatch_async(dispatch_get_main_queue(), ^{
55        // Set the UNUserNotificationCenterDelegate to a class adhering to thie protocol.
56        // In this exmple, the AppDelegate class adheres to the protocol (see below)
57        // and handles Notification Center delegate methods from iOS.
58        [UNUserNotificationCenter currentNotificationCenter].delegate = self;
59
60        // Your application should register for remote notifications each time your application
61        // launches to make sure that the push token for silent push is updated, if necessary.
62
63        // Registering in this manner doesn't mean that a user sees a notification. It only means
64        // that the application will receive a unique push token from iOS.
65        [[UIApplication sharedApplication] registerForRemoteNotifications];
66
67        // Request authorization from the user for push notification alerts.
68        [[UNUserNotificationCenter currentNotificationCenter]
69        requestAuthorizationWithOptions:UNAuthorizationOptionAlert |
70        UNAuthorizationOptionSound |
71        UNAuthorizationOptionBadge
72        completionHandler:^(BOOL granted, NSError *_Nullable error) {
73            if (error == nil) {
74                if (granted == YES) {
75                    // Your application may want to do something specific if the user has granted authorization
76                    // for the notification types specified; it would be done here.
77                    NSLog(@"User granted permission");
78                }
79            }
80        }];
81    });
82}
83
84- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
85    [SFMCSdk requestPushSdk:^(id<PushInterface> _Nonnull mp) {
86        [mp setDeviceToken:deviceToken];
87    }];
88}
89
90- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
91    os_log_debug(OS_LOG_DEFAULT, "didFailToRegisterForRemoteNotificationsWithError = %@", error);
92}
93
94// The method will be called on the delegate when the user responded to the notification by opening
95// the application, dismissing the notification or choosing a UNNotificationAction. The delegate
96// must be set before the application returns from applicationDidFinishLaunching:.
97- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
98    // tell the MarketingCloudSDK about the notification
99    [SFMCSdk requestPushSdk:^(id<PushInterface> _Nonnull mp) {
100        [mp setNotificationResponse:response];
101    }];
102    if (completionHandler != nil) {
103        completionHandler();
104    }
105}
106
107// The method will be called on the delegate only if the application is in the foreground. If the method is not implemented or the handler is not called in a timely manner then the notification will not be presented. The application can choose to have the notification presented as a sound, badge, alert and/or in the notification list. This decision should be based on whether the information in the notification is otherwise visible to the user.
108- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
109    completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
110}
111
112/** This delegate method offers an opportunity for applications with the "remote-notification" background mode to fetch appropriate new data in response to an incoming remote notification. You should call the fetchCompletionHandler as soon as you’re finished performing that operation, so the system can accurately estimate its power and data cost.
113This method will be invoked even if the application was launched or resumed because of the remote notification. The respective delegate methods will be invoked first. Note that this behavior is in contrast to application:didReceiveRemoteNotification:, which is not called in those cases, and which will not be invoked if this method is implemented. **/
114- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
115    [SFMCSdk requestPushSdk:^(id<PushInterface> _Nonnull mp) {
116        [mp setNotificationUserInfo:userInfo];
117    }];
118    completionHandler(UIBackgroundFetchResultNewData);
119}
120
121@end

URL Handling 

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

  • CloudPages URLs from push notifications
  • OpenDirect URLs from push notifications
  • Action URLs from in-app messages

To handle URLs from push notifications, follow these steps.

  1. Set the setURLHandlingDelegate.
  2. Implement the URLHandlingDelegate.

Set the setURLHandlingDelegate 

To set the URLHandlingDelegate, update the AppDelegate as shown in this example.

Swift
1func setupMobilePush() {
2    // Set the URLHandlingDelegate to a class adhering to the protocol.
3    // In this example, the AppDelegate class adheres to the protocol (see below)
4    // and handles URLs passed back from the SDK.
5    // For more information, see https://salesforce-marketingcloud.github.io/MarketingCloudSDK-iOS/sdk-implementation/implementation-urlhandling.html
6    SFMCSdk.requestPushSdk { mp in
7        mp.setURLHandlingDelegate(self)
8    }
9
10    //rest of setupMobilePush...
11}
Objective-C
1// AppDelegate.h
2
3#import <Flutter/Flutter.h>
4#import <UIKit/UIKit.h>
5#import <UserNotifications/UserNotifications.h>
6#import <SFMCSDK/SFMCSDK.h>
7
8//...
9
10// Implement the SFMCSdkURLHandlingDelegate delegate
11@interface AppDelegate : FlutterAppDelegate<UNUserNotificationCenterDelegate, SFMCSdkURLHandlingDelegate>
12
13@end
14
15
16// AppDelegate.m
17
18- (void)pushSetup {
19    // AppDelegate adheres to the SFMCSdkURLHandlingDelegate protocol
20    // and handles URLs passed back from the SDK in `sfmc_handleURL`.
21    // For more information, see https://salesforce-marketingcloud.github.io/MarketingCloudSDK-iOS/sdk-implementation/implementation-urlhandling.html
22    [SFMCSdk requestPushSdk:^(id<PushInterface> _Nonnull mp) {
23        [mp setURLHandlingDelegate:self];
24    }];
25
26    //rest of pushSetup...
27}

Implement the URLHandlingDelegate 

Implement the URLHandlingDelegate in AppDelegate, as shown in this example.

Swift
1// AppDelegate.swift
2
3//rest of AppDelegate.swift...
4
5// MobilePush SDK: REQUIRED IMPLEMENTATION
6extension AppDelegate: URLHandlingDelegate {
7    /**
8     This method, if implemented, can be called when a Alert+CloudPage, Alert+OpenDirect, Alert+Inbox or Inbox message is processed by the SDK.
9     Implementing this method allows the application to handle the URL from Marketing Cloud Engagement data.
10
11     Prior to the MobilePush SDK version 6.0.0, the SDK would automatically handle these URLs and present them using a SFSafariViewController.
12
13     Given security risks inherent in URLs and web pages (Open Redirect vulnerabilities, especially), the responsibility of processing the URL shall be held by the application implementing the MobilePush SDK. This reduces risk to the application by affording full control over processing, presentation and security to the application code itself.
14
15     @param url value NSURL sent with the Location, CloudPage, OpenDirect or Inbox message
16     @param type value NSInteger enumeration of the source type of this URL
17     */
18    func sfmc_handleURL(_ url: URL, type: String) {
19        // Very simply, send the URL returned from the MobilePush SDK to UIApplication to handle correctly.
20        UIApplication.shared.open(url,
21                                  options: [:],
22                                  completionHandler: {
23            (success) in
24            print("Open \(url): \(success)")
25        })
26    }
27}
Objective-C
1// AppDelegate.m
2
3//rest of AppDelegate.m...
4
5/**
6 This method, if implemented, can be called when a Alert+CloudPage, Alert+OpenDirect, Alert+Inbox or Inbox message is processed by the SDK.
7 Implementing this method allows the application to handle the URL from Marketing Cloud Engagement data.
8
9 Prior to the MobilePush SDK version 6.0.0, the SDK would automatically handle these URLs and present them using a SFSafariViewController.
10
11 Given security risks inherent in URLs and web pages (Open Redirect vulnerabilities, especially), the responsibility of processing the URL shall be held by the application implementing the MobilePush SDK. This reduces risk to the application by affording full control over processing, presentation and security to the application code itself.
12
13 @param url value NSURL sent with the Location, CloudPage, OpenDirect or Inbox message
14 @param type value NSInteger enumeration of the source type of this URL
15 */
16- (void)sfmc_handleURL:(NSURL * _Nonnull)url type:(NSString * _Nonnull)type {
17    if ([[UIApplication sharedApplication] canOpenURL:url]) {
18        [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
19            if (success) {
20                NSLog(@"url %@ opened successfully", url);
21            } else {
22                NSLog(@"url %@ could not be opened", url);
23            }
24        }];
25    }
26}
27
28//rest of AppDelegate.m...

Also review the additional documentation on URL Handling

Enable Rich Notifications (Optional) 

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

For implementation details, see Send Rich Notifications.

Troubleshoot iOS Setup 

If you encounter a cycle error in your Flutter Xcode project after adding a Notification Service Extension, follow these steps to fix it.

  1. Navigate to YOUR_APP_TARGET in Xcode.
  2. With your app target selected, go to the Build Phases tab.
  3. Find Embed Foundation Extension.
  4. Drag and position it above both Thin Binary and Embed Pods Frameworks.

Reordering the build phases resolves the cycle error.

See Also