iOS 10系统对推送通知做了较大增强,远程推送通知相关主要体现在以下几点:
总的来说,iOS 10提供了更简洁易用的通知相关接口,提高了处理通知的自由度。
阿里云移动推送对iOS 10通知相关feature配置,通过OpenAPI高级推送接口配置,请参考OpenAPI推送高级接口。
阅读本文档时,可参照iOS推送Demo中iOS 10通知相关的代码进行学习和试用。
UserNotifications.framework
,iOS 10通知相关类和接口都包含在内;
#import <UserNotifications/UserNotifications.h>
Summary
字段设置,参考OpenAPI推送高级接口字段,老版本服务端推送通知payload字段
如下:
{
"aps": {
"alert": {
"your notification body",
},
"badge": 1,
"sound": "default",
},
"key1":"value1",
"key2":"value2"
}
标题(title)
、副标题(subtitle)
、内容(body)
、通知扩展字段(mutable-content)
、通知类别(category)
,服务端配置参考上述的OpenAPI推送高级接口,当前服务端推送通知payload字段
参考如下:
{
"aps": {
"alert": {
"title": "title",
"subtitle": "subtitle",
"body": "body"
},
"badge": 1,
"sound": "default",
"category": "test_category",
"mutable-content": 1
},
"key1":"value1",
"key2":"value2"
}
【注意】使用OpenAPI推送时,若没有进行iOS 10通知相关配置,通知payload保持老版本不变,已经保证对老版本payload兼容性;若进行iOS 10通知相关配置,请确保客户端业务逻辑对payload相关字段处理的兼容性。
iOS 10设备收到通知效果如下,其中标题
为”aliyun”,副标题
为”push”,内容
为”haha”。title
设置后,iOS 10+系统显示title如下;【iOS 8.2 <= iOS系统 < iOS 10】,通知应用名称会显示该标题。
UNUserNotificationCenter
对象进行通知的调度和管理通知相关的行为,具体如下:
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
requestAuthorizationWithOptions
请求授权时,App会弹出如下图所示的授权框,注意App卸载重装前该授权框仅弹出一次,若用户点击“不允许”,需要引导用户到“设置”中打开,推送功能才能正常使用。requestAuthorizationWithOptions
回调中可捕获用户是否点击授权,在成功授权回调中调用registerForRemoteNotifications
,向APNs注册获取设备的deviceToken,App再次启动时虽然不会弹出授权框,但推送授权请求可获取App推送配置,可触发成功/失败授权回调。getNotificationSettingsWithCompletionHandler
接口,回调中可获取App推送授权状态。
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注册成功回调,将返回的deviceToken上传到CloudPush服务器
*/
- (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注册失败回调
*/
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"Get deviceToken failed, error: %@", error);
}
// 主动获取设备通知是否授权(iOS 10+)
- (void)getNotificationSettingStatus {
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
NSLog(@"User authed.");
} else {
NSLog(@"User denied.");
}
}];
}
Action
点击动作,即在通知上添加按钮,点击按钮可触发回调以此做出不同的逻辑处理;Category
分类,可将Action
和Category
进行关联,Category
和第6节(通知详情自定义UI)相关。action1
和action2
的通知动作,创建id为test_category
的通知类别后,将两个Action关联到该category,最后注册category到通知中心。setiOSNotificationCategory()
接口,可指定通知的类别;创建的test_category
类别的通知弹出时如下图所示,test1
和test2
按钮分别对应id为action1
和action2
的通知Action;Category
注册到通知中心需要在推送前完成。
/**
* 创建并注册通知category(iOS 10+)
*/
- (void)createCustomNotificationCategory {
// 自定义`action1`和`action2`
UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"action1" title:@"test1" options: UNNotificationActionOptionNone];
UNNotificationAction *action2 = [UNNotificationAction actionWithIdentifier:@"action2" title:@"test2" options: UNNotificationActionOptionNone];
// 创建id为`test_category`的category,并注册两个action到category
// UNNotificationCategoryOptionCustomDismissAction表明可以触发通知的dismiss回调
UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:@"test_category" actions:@[action1, action2] intentIdentifiers:@[] options:
UNNotificationCategoryOptionCustomDismissAction];
// 注册category到通知中心
[center setNotificationCategories:[NSSet setWithObjects:category, nil]];
}
UNUserNotificationCenterDelegate
协议定义了通知相关的回调;UNUserNotificationCenter
的代理UNUserNotificationCenterDelegate
,一般是在AppDelegate中实现,如下所示:
@interface AppDelegate () <UNUserNotificationCenterDelegate>
@end
@implementation AppDelegate
...
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
...
@end
userNotificationCenter:willPresentNotification:withCompletionHandler:
回调;completionHandler(UNNotificationPresentationOptions)
,UNNotificationPresentationOptions
的参数含义如下:UNNotificationPresentationOptionNone
,通知不提醒;UNNotificationPresentationOptionSound
,通知声音提醒;UNNotificationPresentationOptionAlert
,通知内容提醒;UNNotificationPresentationOptionBadge
,通知角标提醒。
/**
* 处理iOS 10通知(iOS 10+)
*/
- (void)handleiOS10Notification:(UNNotification *)notification {
UNNotificationRequest *request = notification.request;
UNNotificationContent *content = request.content;
NSDictionary *userInfo = content.userInfo;
// 通知时间
NSDate *noticeDate = notification.date;
// 标题
NSString *title = content.title;
// 副标题
NSString *subtitle = content.subtitle;
// 内容
NSString *body = content.body;
// 角标
int badge = [content.badge intValue];
// 取得通知自定义字段内容,例:获取key为"Extras"的内容
NSString *extras = [userInfo valueForKey:@"Extras"];
// 通知打开回执上报
[CloudPushSDK handleReceiveRemoteNotification:userInfo];
NSLog(@"Notification, date: %@, title: %@, subtitle: %@, body: %@, badge: %d, extras: %@.", noticeDate, title, subtitle, body, badge, extras);
}
/**
* App处于前台时收到通知(iOS 10+)
*/
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
NSLog(@"Receive a notification in foregound.");
// 处理iOS 10通知相关字段信息
[self handleiOS10Notification:notification];
// 通知不弹出
//completionHandler(UNNotificationPresentationOptionNone);
// 通知弹出,且带有声音、内容和角标(App处于前台时不建议弹出通知)
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}
userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
回调里捕获到这些动作,根据UNNotificationResponse.actionIdentifier
可对这些动作进行区分:UNNotificationDefaultActionIdentifier
;UNNotificationDismissActionIdentifier
,注册Category
时,需传入UNNotificationCategoryOptionCustomDismissAction
才可以捕获到该动作,具体见4.3节的Category
创建和注册;action1
和action2
的Action,自定义Action
点击动作的捕获的好处在于,即使不进入App同样可完成某些逻辑处理。userNotificationCenter:willPresentNotification:withCompletionHandler:
回调;之后若有点击通知动作,再触发userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
回调。
/**
* 触发通知动作时回调,比如点击、删除通知和点击自定义action(iOS 10+)
*/
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
NSString *userAction = response.actionIdentifier;
// 点击通知打开
if ([userAction isEqualToString:UNNotificationDefaultActionIdentifier]) {
NSLog(@"User opened the notification.");
// 处理iOS 10通知,并上报通知打开回执
[self handleiOS10Notification:response.notification];
}
// 通知dismiss,category创建时传入UNNotificationCategoryOptionCustomDismissAction才可以触发
if ([userAction isEqualToString:UNNotificationDismissActionIdentifier]) {
NSLog(@"User dismissed the notification.");
}
NSString *customAction1 = @"action1";
NSString *customAction2 = @"action2";
// 点击用户自定义Action1
if ([userAction isEqualToString:customAction1]) {
NSLog(@"User custom action1.");
}
// 点击用户自定义Action2
if ([userAction isEqualToString:customAction2]) {
NSLog(@"User custom action2.");
}
completionHandler();
}
Notification Service Extension
,使得通知弹出前可以对通知内容进行修改。Notification Service Extension
后,如下图所示,APNs推送的通知在弹出前,可先到达Extension
进行处理,【注意】OpenAPI需要调用setiOSMutableContent(true)
接口,这样Extension
才可生效。在Service Extension
后台预处理阶段,可从远程服务器下载或从本地获取富媒体
(图片、音频、视频)资源,将其作为attachment
添加到通知中,富媒体资源类型和大小限制如下:
Notification Service Extension
添加步骤:
Notification Service Extension
,如下图所示:NotificationService
的模板,在didReceiveNotificationRequest
回调方法中,处理通知弹出前的动作。attachment
字段中获取图片Url,或者从本地获取图片资源,效果如下图所示。Service Extension
Target进行配置;建议限制为请求HTTPS资源。Notification Service Extension
,另一个通知相关的Extension为内容扩展Content Extension
,可用于自定义通知详情UI,如修改样式、颜色等。Notification Content
,如下图所示:NotificationViewController
头文件和源文件,MainInterface.storyboard
和Info.plist
,其中NotificationViewController
和MainInterface.storyboard
一起定义了通知详情的UI。Info.plist中
自动生成NSExtension
相关KV配置,具体含义如下所示:MainInterface
;(必需)com.apple.usernotifications.content-extension
;(必需)setiOSNotificationCategory
接口指定通知category,只有指定的category在Info.plist的UNNotificationExtensionCategory
设置,才能保证通知详情自定义UI生效。aliyun-body
为自定义的展示UI,字段内容通过拷贝通知内容得来。