App Center Push

Note

Starting with version 1.11.0 of the App Center Push SDK, calling push:didReceivePushNotification: within a UNUserNotificationCenterDelegate is no longer necessary. If you implemented a UNUserNotificationCenterDelegate and are calling the push:didReceivePushNotification: callback, please refer to the App Center SDK migration guide to migrate your code.

App Center Push enables you to send push notifications to users of your app from the App Center portal.

Prerequisite - Enable Apple Push Notifications service (APNs) for your app

Configure Apple Push Notifications service (APNs) for your app from your Apple developer account and App Center portal before adding App Center Push to your app.

Enable push notifications on your application

In Xcode's project editor, choose your target and click Capabilities. In the Push Notifications section, click the switch to turn it from OFF to ON.

enable-push-capability

Set up APNs

Log in to the App Center portal, select your application, click on the Push button from the left menu then click Next to reveal the push notification settings UI:

app-center-push-settings

  • On the bottom of the page, select Sandbox for initial development or Production for production version of your application.

  • Collect the following information:

    1. Prefix and ID

      • Go to your Apple developer account and select your application from the App ID list in Identifiers.

      • Copy the Prefix value from this window and paste it to the App Center push settings.

      • Do the same with the ID value.

      apple-dev-center-app-id

    Note

    As per guidance from the Apple Developer documentation, all new app developers who joined after 2011 will have the Team ID same as the App Prefix ID. If you have joined before, you will need to get the Team ID instead.

    1. Key ID

      • In your Apple developer account create a new key in Certificates, Identifiers & Profiles/Keys.

      • Make sure to check the APNs checkbox.

      • Fill in the key name

      • Press Continue then Confirm.

      apple-dev-center-new-auth-key

      • On the next screen, copy the Key ID value and paste it to the App Center push settings.

      • Download the key file.

      apple-dev-center-confirm-auth-key

    2. Push Token

      • On the App Center push settings page, upload your key file using the button labelled "Auth key file:" (you can also drag and drop the file onto it):

      auth-key-file

      • Click Done to complete this configuration.

For more information, refer to the Apple documentation.

[Optional] Enable silent notifications

Silent notifications give you a way to wake up your app so that it can refresh its data in the background (see Apple documentation). To enable silent notifications open Xcode's project editor, choose your target and click Capabilities. Turn on Background Modes and check the Remote notifications checkbox.

enable-silent-notifications

Note

If there are no user-visible updates that go along with the background update, you can leave the title and message fields empty to prevent showing any visible notifications.

Note

Silent notifications are the mechanism behind background app refresh, the user can open settings (General > Background App Refresh) and disable them. You can't depend on them always being available.

Add App Center Push to your app

1. Add the App Center Push module

The App Center SDK is designed with a modular approach – you only need to integrate the services that you're interested in.

Integration via Cocoapods

If you are integrating App Center into your app via Cocoapods, add the following dependency to your podfile and run pod install.

pod 'AppCenter/Push'

Integration by copying the binaries into your project

If you wish to manually integrate the module, follow this documentation link.

2. Start App Center Push

In order to use App Center, you must opt in to the module(s) that you want to use. By default no modules are started and you will have to explicitly call each of them when starting the SDK.

2.1 Add the import for App Center Push

Open the project's AppDelegate.m file in Objective-C or AppDelegate.swift file in Swift and add the following import statements:

@import AppCenter;
@import AppCenterPush;
import AppCenter
import AppCenterPush

2.2 Add the start:withServices: method

Add MSPush to your start:withServices: method to start App Center Push together with the other services that you want to use in your app.

Insert the following line to start the SDK in the project's AppDelegate.m class in Objective-C or AppDelegate.swift class in Swift in the didFinishLaunchingWithOptions method.

[MSAppCenter start:@"{Your App Secret}" withServices:@[[MSPush class]]];
MSAppCenter.start("{Your App Secret}", withServices: [MSPush.self])

Make sure you have replaced {Your App Secret} in the code sample above with your App Secret. Please also check out the Get started section if you haven't configured the SDK in your application.

Note

The first time App Center Push starts, the system may prompt the user to grant the application permission to send notifications. To delay this prompt, start App Center Push later by omitting the MSPush class from the start:withServices: method. When you're ready to prompt the user, call the startService: method and pass the MSPush class. For all subsequent app launches, start MSPush as early as possible to ensure that all push notifications are captured.

Intercept push notifications

You can set up a delegate to be notified whenever a push notification is received in foreground or a background push notification has been tapped by the user. The delegate may also be woken up when a notification is received in background if you have enabled silent notifications and if the payload of the notification contains the content-available flag set to true.

Note

If silent notifications are enabled and you push a notification with content-available: 1, then the delegate may be triggered twice for the same notification: when the notification is received in background and when it is tapped.

By default, iOS does not generate notifications when the push is received in foreground, you can use the delegate to customize the push experience when received in foreground or do a specific action when the application is launched by clicking on the push notification when received in background.

You need to register the delegate before starting App Center as shown in the following example:

[MSPush setDelegate:self];
[MSAppCenter start:@"{Your App Secret}" withServices:@[[MSPush class]]];
MSPush.setDelegate(self)
MSAppCenter.start("{Your App Secret}", withServices: [MSPush.self])

Here is an example of the delegate implementation that displays an alert dialog when the message is received by App Center Push:

- (void)push:(MSPush *)push didReceivePushNotification:(MSPushNotification *)pushNotification {
  NSString *title = pushNotification.title ?: @"";
  NSString *message = pushNotification.message;
  NSMutableString *customData = nil;
  for (NSString *key in pushNotification.customData) {
    ([customData length] == 0) ? customData = [NSMutableString new] : [customData appendString:@", "];
    [customData appendFormat:@"%@: %@", key, [pushNotification.customData objectForKey:key]];
  }
  if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) {
    NSLog(@"Notification received in background, title: \"%@\", message: \"%@\", custom data: \"%@\"", title, message,
          customData);
  } else {
    message = [NSString stringWithFormat:@"%@%@%@", (message ? message : @""), (message && customData ? @"\n" : @""),
                                         (customData ? customData : @"")];

    UIAlertController *alertController =
        [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];

    // Show the alert controller.
    [self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  }
}
func push(_ push: MSPush!, didReceive pushNotification: MSPushNotification!) {
  let title: String = pushNotification.title ?? ""
  var message: String = pushNotification.message ?? ""
  var customData: String = ""
  for item in pushNotification.customData {
    customData =  ((customData.isEmpty) ? "" : "\(customData), ") + "\(item.key): \(item.value)"
  }
  if (UIApplication.shared.applicationState == .background) {
    NSLog("Notification received in background, title: \"\(title)\", message: \"\(message)\", custom data: \"\(customData)\"");
  } else {
    message =  message + ((customData.isEmpty) ? "" : "\n\(customData)")

    let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
    alertController.addAction(UIAlertAction(title: "OK", style: .cancel))

    // Show the alert controller.
    self.window?.rootViewController?.present(alertController, animated: true)
  }
}

Custom data in your notifications

You can send optional custom data as part of the push payload. The data will be sent in the key-value format. This custom data can be intercepted in the app through Push SDK callback.

There are few reserved keywords that can be set via custom data.

Reserved keywords in iOS platform

  • badge: Add this key when you want to modify the badge of your app icon. If this key is not included, the badge is not changed. To remove the badge, set the value of this key to 0.
  • sound: Add this key when you want the to play a sound. The value of this key is the name of a sound file in your app's main bundle or in the Library/Sounds folder of your app’s data container. If the sound file cannot be found, or if you specify default for the value, the system plays the default alert sound.
  • content-available: Add this key with a value of 1 to configure a silent notification. When this key is present, the system wakes up your app in the background and delivers the notification to its app delegate. For information about configuring and handling silent notifications, see Configuring a Silent Notification.
  • mutable-content: Add this key with a value of 1 to enable media attachments. The application needs to support a service extension to download and handle the attachment content. For more information you can refer to Apple documentations.

Enable or disable App Center Push at runtime

You can enable and disable App Center Push at runtime. If you disable it, the SDK will stop updating the device token used to push but the existing one will continue working. In other words, disabling the App Center Push in the SDK will NOT stop your application from receiving push notifications.

[MSPush setEnabled:NO];
MSPush.setEnabled(false)

To enable App Center Push again, use the same API but pass YES/true as a parameter.

[MSPush setEnabled:YES];
MSPush.setEnabled(true)

The state is persisted in the device's storage across application launches.

Note

This method must only be used after MSPush has been started.

Check if App Center Push is enabled

You can also check if App Center Push is enabled or not:

BOOL enabled = [MSPush isEnabled];
var enabled = MSPush.isEnabled()

Note

This method must only be used after MSPush has been started, it will always return NO or false before start.

Disable automatic method forwarding to App Center services

App Center uses swizzling to automatically forward your application delegate's methods to App Center services to improve SDK integration. Method swizzling is a way to change implementation of methods at runtime. There is a possibility of conflicts with other third party libraries or the application delegate itself. You may want to disable the App Center application delegate forwarding for all App Center services by following the steps below:

Application Delegate

  1. Open the project's Info.plist file.

  2. Add the AppCenterAppDelegateForwarderEnabled key, and set the value to 0. This disables application delegate forwarding for all App Center services.

  3. Implement the callbacks to register push notifications

    Implement the application:didRegisterForRemoteNotificationsWithDeviceToken: callback and the application:didFailToRegisterForRemoteNotificationsWithError: callback in your AppDelegate to register for Push notifications.

    - (void)application:(UIApplication *)application
        didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    
      // Pass the device token to MSPush.
      [MSPush didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
    }
    
    - (void)application:(UIApplication *)application
        didFailToRegisterForRemoteNotificationsWithError:(nonnull NSError *)error {
    
      // Pass the error to MSPush.
      [MSPush didFailToRegisterForRemoteNotificationsWithError:error];
    }
    
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    
      // Pass the device token to MSPush.
      MSPush.didRegisterForRemoteNotifications(withDeviceToken: deviceToken)
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    
      // Pass the error to MSPush.
      MSPush.didFailToRegisterForRemoteNotificationsWithError(error)
    }
    
  4. Implement the callback to receive push notifications

    Implement the application:didReceiveRemoteNotification:fetchCompletionHandler callback to forward push notifications to App Center Push.

    - (void)application:(UIApplication *)application
        didReceiveRemoteNotification:(NSDictionary *)userInfo
              fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
      BOOL result = [MSPush didReceiveRemoteNotification:userInfo];
      if (result) {
        completionHandler(UIBackgroundFetchResultNewData);
      } else {
        completionHandler(UIBackgroundFetchResultNoData);
      }
    }
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
      let result: Bool = MSPush.didReceiveRemoteNotification(userInfo)
      if result {
        completionHandler(.newData)
      }
      else {
        completionHandler(.noData)
      }
    }
    

User Notification Center Delegate

  1. Open the project's Info.plist file.

  2. Add the AppCenterUserNotificationCenterDelegateForwarderEnabled key, and set the value to 0. This disables UNUserNotificationCenter delegate forwarding for App Center Push.

  3. Implement UNUserNotificationCenterDelegate callbacks and pass the notification's payload to App Center Push.

    - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options)) completionHandler API_AVAILABLE(ios(10.0)) {
    
      //...
    
      // Pass the notification payload to MSPush.
      [MSPush didReceiveRemoteNotification:notification.request.content.userInfo];
    
      // Complete handling the notification.
      completionHandler(UNNotificationPresentationOptionNone);
    }
    
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10.0)) {
    
      //...
    
      // Pass the notification payload to MSPush.
      [MSPush didReceiveRemoteNotification:response.notification.request.content.userInfo];
    
      // Complete handling the notification.
      completionHandler();
    }
    
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    
      //...
    
      // Pass the notification payload to MSPush.
      MSPush.didReceiveRemoteNotification(notification.request.content.userInfo)
    
      // Complete handling the notification.
      completionHandler([])
    }
    
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    
      //...
    
      // Pass the notification payload to MSPush.
      MSPush.didReceiveRemoteNotification(response.notification.request.content.userInfo)
    
      // Complete handling the notification.
      completionHandler()
    }
    

Common tasks for push notifications

Handle a push notification while the app is in foreground

App Center Push allows apps to intercept push notifications and react to them, e.g. to display an alert, as described in the App Center Push documentation above. In some cases, it is helpful to distinguish between push notifications received while the app is in the foreground or background, and handle them differently. The App Center SDK-provided callback is not enough in this case since the application's state will always be reported as active.

To distinguish between notifications received in the foreground and notifications received while the app was in the background, you must implement one of the callbacks defined in UNUserNotificationDelegate. Please see Apple's documentation for more details.

Note

The solution below requires iOS 10 or later.

  1. In your AppDelegate and add import in the top of file:

    #import <UserNotifications/UserNotifications.h>
    
    import UserNotifications
    
  2. Add the following to the didFinishLaunching:withOptions: to register as a UNUserNotificationCenterDelegate:

    if (@available(iOS 10.0, *)) {
      UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
      center.delegate = self;
    }
    
    if #available(iOS 10.0, *) {
      UNUserNotificationCenter.current().delegate = self
    }
    
  3. Implement the following callback to detect a foreground notification:

    // iOS 10 and later, called when a notification is delivered to an app that is in the foreground.
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center
          willPresentNotification:(UNNotification *)notification
            withCompletionHandler:(void (^)(UNNotificationPresentationOptions options)) completionHandler API_AVAILABLE(ios(10.0)) {
    
        // Do something, e.g. set a BOOL @property to track the foreground state.
        self.didReceiveNotificationInForeground = YES;
    
        // Complete handling the notification.
        completionHandler(UNNotificationPresentationOptionNone);
    }
    
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    
        // Do something, e.g. set a Bool property to track the foreground state.
        self.didReceiveNotificationInForeground = true
    
        // Complete handling the notification.
        completionHandler([])
    }
    
  4. (Optional) If you have implemented the App Center Push SDK push:didReceivePushNotification: callback, you should adjust its behavior to a handle the foreground detection:

    - (void)push:(MSPush *)push didReceivePushNotification:(MSPushNotification *)pushNotification {
    
        // Do something differently if the push notification was received while in foreground.
        if (self.didReceiveNotificationInForeground) {
    
            // Handle the push notification that was received while in foreground.
        } else {
    
            // Handle the push notification that was received while app was in background.
        }
    
        // Reset the property for next notifications.
        self.didReceiveNotificationInForeground = NO;
    }
    
    @available(iOS 10.0, *)
    func push(_ push: MSPush!, didReceive pushNotification: MSPushNotification!) {
    
        // Do something differently if the push notification was received while in foreground.
        if (self.didReceiveNotificationInForeground) {
    
            // Handle the push notification that was received while in foreground
        } else {
    
            // Handle the push notification that was received while app was in background.
        }
    
        // Reset the property for next notifications.
        self.didReceiveNotificationInForeground = false
    }
    

Detecting when a user has tapped on a push notification

Sometimes it is helpful to determine if user has tapped push notification. To perform this task you must implement one of the callbacks defined in UNUserNotificationDelegate. Please see Apple's documentation for more details.

Note

The solution below requires iOS 10 or later.

  1. In your AppDelegate and add import in the top of file:

    #import <UserNotifications/UserNotifications.h>
    
    import UserNotifications
    
  2. Add the following to the didFinishLaunching:withOptions: to register as a UNUserNotificationCenterDelegate:

    if (@available(iOS 10.0, *)) {
      UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
      center.delegate = self;
    }
    
    if #available(iOS 10.0, *) {
      UNUserNotificationCenter.current().delegate = self
    }
    
  3. Implement the following callback to detect various actions performed by users with push notifications:

    // iOS 10 and later, asks the delegate to process the user's response to a delivered notification.
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center
        didReceiveNotificationResponse:(UNNotificationResponse *)response
                withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10.0)) {
    
      // Perform the task associated with the action.
      if ([[response actionIdentifier] isEqualToString:UNNotificationDefaultActionIdentifier]) {
    
        // User tapped on notification
      }
    
      // Complete handling the notification.
      completionHandler();
    }
    
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center:UNUserNotificationCenter,didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    
      // Perform the task associated with the action.
      if (response.actionIdentifier == UNNotificationDefaultActionIdentifier) {
    
        // User tapped on notification.
      }
    
      // Complete handling the notification.
      completionHandler()
    }