Adapting to iOS 10 notifications

更新时间:
复制 MD 格式

1. Introduction to iOS 10 notifications

iOS 10 significantly enhances push notifications. The main changes for remote push notifications include the following:

  • Unified APIs and frameworks for notifications.

  • Modified notification registration and callback interfaces.

  • Richer notification content that supports rich media, such as images, audio, and videos.

  • Customizable UI for notification details.

Overall, iOS 10 provides simpler and more user-friendly notification interfaces, which gives you more freedom to handle notifications.

Note

Alibaba Cloud Mobile Push uses the advanced push API of OpenAPI to configure iOS 10 notification features. For more information, see Advanced push API. You can also refer to the iOS 10 notification code in the iOS push demo for learning and testing.

2. Framework dependencies

  • The UserNotifications.framework contains all classes and interfaces related to iOS 10 notifications.

  • You can reference it as follows:

#import <UserNotifications/UserNotifications.h>

3. Notification fields

  • Previously, iOS notifications only supported setting the notification content. You set this value using the Summary field in OpenAPI. For more information about the field, see Advanced push API. The server-side push notification payload for earlier versions is as follows:

{
    "aps": {
        "alert": {
        "your notification body",
        },
        "badge": 1,
        "sound": "default",
    },
    "key1":"value1",
    "key2":"value2"
}
  • iOS 10 notifications support the title, subtitle, body, mutable-content, and category fields. The mutable-content field is used for notification extensions. For server-side configuration, see the advanced push API mentioned earlier. The current server-side push notification payload is as follows:

{
    "aps": {
        "alert": {
            "title": "title",
            "subtitle": "subtitle",
            "body": "body"
        },
        "badge": 1,
        "sound": "default",
        "category": "test_category",
        "mutable-content": 1
    },
    "key1":"value1",
    "key2":"value2"
}
Important

When you use OpenAPI to send pushes, if you do not configure settings for iOS 10 notifications, the notification payload remains the same as in earlier versions to ensure backward compatibility. If you configure settings for iOS 10 notifications, ensure that your client-side business logic is compatible with the payload fields.

  • The following image shows how a notification appears on an iOS 10 device. The title is "aliyun", the subtitle is "push", and the body is "haha". After you set the title, it is displayed as shown on iOS 10 and later. On systems from iOS 8.2 to versions earlier than iOS 10, this title is displayed instead of the application name.

ios10-fit

4. Notification center

4.1 Introduction

  • You can use the UNUserNotificationCenter object to schedule notifications and manage notification-related behaviors, such as:

    • Requesting authorization for alerts, sounds, and badges.

    • Declaring notification categories and executable actions.

    • Managing the display of notifications.

    • Managing how notifications are presented in the device's notification center.

    • Retrieving the notification-related settings for your application.

  • You can retrieve the notification center object as follows:

    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];

4.2 Request authorization and register with APNs

  • Before your application can use the push feature, it must request authorization from the user, as shown in the following code.

  • The first time you call requestAuthorizationWithOptions to request authorization, the application displays an authorization dialog box as shown in the following figure. Note that this dialog box appears only once until the application is uninstalled and reinstalled. If the user taps "Don't Allow", you must guide the user to enable notifications in "Settings" to use the push feature.

iOS10-notice-auth

  • In the requestAuthorizationWithOptions callback, you can determine whether the user granted authorization. In the success callback, call registerForRemoteNotifications to register with the Apple Push Notification service (APNs) and retrieve the device token. When the application starts again, the authorization dialog box does not appear, but the push authorization request can retrieve the application's push settings and trigger the success or failure callback.

  • The APNs registration success and failure callbacks remain unchanged. In the success callback, you can call the Alibaba Cloud Mobile Push software development kit (SDK) interface to report the device token to the Alibaba Cloud Mobile Push server.

  • You can call the getNotificationSettingsWithCompletionHandler interface. In the callback, you can retrieve the application's push authorization status.

UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
if (systemVersionNum >= 10.0) {
    center = [UNUserNotificationCenter currentNotificationCenter];
    [center requestAuthorizationWithOptions:UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            // Granted
            NSLog(@"User authored notification.");
            dispatch_async(dispatch_get_main_queue(), ^{
                [application registerForRemoteNotifications];
            };
        } else {
            // Not granted
            NSLog(@"User denied notification.");
        }
    }];
}

/*
 *  APNs registration success callback. Upload the returned deviceToken to the CloudPush server.
 */
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"Upload deviceToken to CloudPush server.");
    [CloudPushSDK registerDevice:deviceToken withCallback:^(CloudPushCallbackResult *res) {
        if (res.success) {
            NSLog(@"Register deviceToken success, deviceToken: %@", [CloudPushSDK getApnsDeviceToken]);
        } else {
            NSLog(@"Register deviceToken failed, error: %@", res.error);
        }
    }];
}

/*
 *  APNs registration failed callback.
 */
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Get deviceToken failed, error: %@", error);
}

// Actively get the notification authorization status of the device (iOS 10+).
- (void)getNotificationSettingStatus {
    [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
        if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
            NSLog(@"User authed.");
        } else {
            NSLog(@"User denied.");
        }
    }];
}

4.3 Actions and categories

  • This feature is supported on iOS 8 and later. This section describes only the implementation for iOS 10.

  • Notifications support clickable Actions. This means you can add buttons to a notification. Tapping a button can trigger a callback to handle specific logic.

  • Notifications support Category classification. You can associate an Action with a Category. The Category is related to the information in Section 6, Customizing the UI for notification details.

  • The following code defines notification actions with the IDs action1 and action2. It then creates a notification category with the ID test_category, associates the two actions with this category, and finally registers the category with the notification center.

  • When you send a push notification using OpenAPI, you can call the setiOSNotificationCategory() interface to specify the notification category. When a notification of the test_category type is displayed, it appears as shown in the following figure. The test1 and test2 buttons correspond to the notification actions with the IDs action1 and action2.

  • Note The Category must be registered with the notification center before you send the push.

ios10-category

/**
 *  Create and register a notification category (iOS 10+).
 */
- (void)createCustomNotificationCategory {
    // Define `action1` and `action2`.
    UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"action1" title:@"test1" options: UNNotificationActionOptionNone];
    UNNotificationAction *action2 = [UNNotificationAction actionWithIdentifier:@"action2" title:@"test2" options: UNNotificationActionOptionNone];
    // Create a category with the ID `test_category` and register the two actions with the category.
    // UNNotificationCategoryOptionCustomDismissAction indicates that the notification's dismiss callback can be triggered.
    UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:@"test_category" actions:@[action1, action2] intentIdentifiers:@[] options:
                                        UNNotificationCategoryOptionCustomDismissAction];
    // Register the category with the notification center.
    [center setNotificationCategories:[NSSet setWithObjects:category, nil]];
}

4.4 Notification callbacks

  • The UNUserNotificationCenterDelegate protocol defines notification-related callbacks.

4.4.1 Configuring the agent

  • To handle notification-related callbacks, you must implement UNUserNotificationCenterDelegate and set it as the delegate for the UNUserNotificationCenter object. This is typically done in the AppDelegate, as follows:

@interface AppDelegate () <UNUserNotificationCenterDelegate>
@end

@implementation AppDelegate
...
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
...
@end

4.4.2 Callback 1: Application receives a notification in the foreground

  • When the application is in the foreground, receiving a notification triggers the userNotificationCenter:willPresentNotification:withCompletionHandler: callback.

  • In the callback, you can process the information in the notification fields. Before the callback finishes, you must call completionHandler(UNNotificationPresentationOptions). The parameters for UNNotificationPresentationOptions are as follows:

    • UNNotificationPresentationOptionNone: The notification is not displayed.

    • UNNotificationPresentationOptionSound: A sound is played for the notification.

    • UNNotificationPresentationOptionAlert: The notification content is displayed.

    • UNNotificationPresentationOptionBadge: The application icon badge is updated.

  • This way, you can also display notifications when the application is in the foreground.

/**
 *  Handle iOS 10 notifications (iOS 10+).
 */
- (void)handleiOS10Notification:(UNNotification *)notification {
    UNNotificationRequest *request = notification.request;
    UNNotificationContent *content = request.content;
    NSDictionary *userInfo = content.userInfo;
    // Notification time
    NSDate *noticeDate = notification.date;
    // Title
    NSString *title = content.title;
    // Subtitle
    NSString *subtitle = content.subtitle;
    // Body
    NSString *body = content.body;
    // Badge
    int badge = [content.badge intValue];
    // Get the content of custom notification fields. For example, get the content for the key "Extras".
    NSString *extras = [userInfo valueForKey:@"Extras"];
    // Report the receipt for opening the notification.
    [CloudPushSDK handleReceiveRemoteNotification:userInfo];
    NSLog(@"Notification, date: %@, title: %@, subtitle: %@, body: %@, badge: %d, extras: %@.", noticeDate, title, subtitle, body, badge, extras);
}

/**
 *  The application receives a notification while in the foreground (iOS 10+).
 */
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    NSLog(@"Receive a notification in foregound.");
    // Process iOS 10 notification-related field information.
    [self handleiOS10Notification:notification];
    // Do not display the notification.
    //completionHandler(UNNotificationPresentationOptionNone);
    // Display the notification with sound, content, and badge. (Displaying notifications is not recommended when the application is in the foreground).
    completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}

4.4.3 Callback 2: Tap or clear a notification

  • When a user taps or clears a notification, you can handle these actions in the userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: callback. You can differentiate between these actions based on UNNotificationResponse.actionIdentifier:

    • Tapping the notification to open the application corresponds to UNNotificationDefaultActionIdentifier.

    • Swiping left to delete the notification corresponds to UNNotificationDismissActionIdentifier. To handle this action, you must pass UNNotificationCategoryOptionCustomDismissAction when you register the Category. For more information about Category creation and registration, see Section 4.3.

    • Tapping a custom action, such as the actions with the IDs action1 and action2 that were created in Section 4.3. The benefit of handling custom Action clicks is that you can execute logic without opening the application.

  • Note The two notification callbacks do not conflict. When the application is in the foreground, receiving a notification first triggers the userNotificationCenter:willPresentNotification:withCompletionHandler: callback. If the user then taps the notification, the userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: callback is triggered.

/**
 *  Callback for when a notification action is triggered, such as tapping or deleting a notification, or tapping a custom action (iOS 10+).
 */
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    NSString *userAction = response.actionIdentifier;
    // Tapped to open the notification.
    if ([userAction isEqualToString:UNNotificationDefaultActionIdentifier]) {
        NSLog(@"User opened the notification.");
        // Handle the iOS 10 notification and report the receipt for opening it.
        [self handleiOS10Notification:response.notification];
    }
    // Notification dismissed. This is triggered only if UNNotificationCategoryOptionCustomDismissAction was passed when the category was created.
    if ([userAction isEqualToString:UNNotificationDismissActionIdentifier]) {
        NSLog(@"User dismissed the notification.");
    }
    NSString *customAction1 = @"action1";
    NSString *customAction2 = @"action2";
    // User tapped custom Action1.
    if ([userAction isEqualToString:customAction1]) {
        NSLog(@"User custom action1.");
    }
    // User tapped custom Action2.
    if ([userAction isEqualToString:customAction2]) {
        NSLog(@"User custom action2.");
    }
    completionHandler();
}

5. Rich media pushes

  • iOS 10 adds the Notification Service Extension, which lets you modify notification content before it is displayed.

  • The process for iOS remote pushes is shown in the following figure. Notifications pushed by APNs are displayed directly on the device.ios-remote-notice

  • After you add a Notification Service Extension, the process is as shown in the following figure. Before a notification pushed by APNs is displayed, it can first be processed by the Extension. Note: You must call the setiOSMutableContent(true) method in OpenAPI for the Extension to take effect.ios-service-extension

  • During the background pre-processing phase in the Service Extension, you can download rich media resources such as images, audio, and videos from a remote server or retrieve them locally. You can then add them to the notification as an attachment. The resource types and size limits for rich media are as follows:ios-media-limit

  • To add a Notification Service Extension, follow these steps:

    • In Xcode, go to File > New > Target and select Notification Service Extension, as shown in the following figure:

    • Enter a name for the target. After creation, Xcode automatically generates a NotificationService template in the directory. In the didReceiveNotificationRequest callback method, handle the actions that must be performed before the notification is displayed.

  • You can refer to the implementation in the iOS Demo Notification Service Extension to send push notifications with images. Retrieve the image URL from the custom attachment parameter field set in OpenAPI, or retrieve the image resource locally. The result is shown in the following figure.

  • Note: When you retrieve rich media resources from a remote server, you must follow the App Transport Security (ATS) principles. To request HTTP resources, you must configure the Service Extension target. For more information, see ATS configuration. We recommend that you restrict requests to HTTPS resources.

ios-pic-notice

6. Customizing the UI for notification details

  • In addition to the Notification Service Extension, another notification-related extension is the Content Extension. You can use it to customize the UI for notification details, such as by modifying styles and colors.

  • After a device receives a notification on iOS 10, you can pull down the notification or use 3D Touch to view the notification details. Note: Testing shows that pulling down a notification is not supported on iPhone 5c. We recommend testing on an iPhone 6 or a later model. The default style for notification details that contain an image is shown in the following figure. You can use a content extension to customize the notification details.

  • To add a content extension, follow these steps:

    • In Xcode, go to File > New > Target and select Notification Content, as shown in the following figure:ios10-notice-content

    • Enter a name for the target. Xcode automatically generates the NotificationViewController header and source files, MainInterface.storyboard, and Info.plist. The NotificationViewController and MainInterface.storyboard together define the UI for the notification details.

    • The Info.plist file automatically generates key-value configurations that are related to NSExtension. The keys are described as follows:

      • NSExtensionAttributes

        • UNNotificationExtensionCategory: Specifies which categories the custom notification details UI applies to. The value can be a string or a dictionary. (Required)

        • UNNotificationExtensionInitialContentSizeRatio: The aspect ratio of the notification view. (Required)

        • UNNotificationExtensionDefaultContentHidden: Specifies whether to hide the original notification content. If this key is not specified, the default value is NO. (Optional)

      • NSExtensionMainStoryboard: The name of the storyboard file. The default is MainInterface. (Required)

      • NSExtensionPointIdentifier: The default is com.apple.usernotifications.content-extension. (Required)

  • When you send a push using OpenAPI, you must use the setiOSNotificationCategory method to specify the notification category. The custom UI for notification details takes effect only if the specified category is also set in the UNNotificationExtensionCategory key of the Info.plist file.

  • You can refer to the implementation in the iOS Demo Notification Content Extension to set a custom UI for notification details. As shown in the following figure, the green aliyun-body is the custom display UI. The content of this field is copied from the notification content.