介绍
User Notifications Framework 是苹果在 WWDC 2016 推出的。iOS 10 中以前杂乱的和通知相关的 API 都被统一了,现在开发者可以使用独立的 UserNotifications.framework 来集中管理和使用 iOS 系统中通知的功能。在此基础上,Apple 还增加了撤回单条通知,更新已展示通知,中途修改通知内容,在通知中展示图片视频,自定义通知 UI 等一系列新功能,非常强大。
iOS 10 以前的推送
iOS 10 以前推送分为 Local Notifications(本地推送) 和 Remote Notifications(远程推送)。
本地推送:通过 App 本地定制,加入到系统的 Schedule 里,然后在指定的时间推送指定文字。
远程推送:通过服务端向苹果推送服务器 Apple Push Notification Service (APNs) 发送 Notification Payload,之后 APNs 再将推送下发到指定设备的 指定 App 上。
User Notifications Framework
基本配置
如果只是简单的本地推送,跳过 1 、2 步骤,直接到步骤 3。
1、 如果你的 App 有远端推送的话,那你需要开发者账号的,需要新建一个对应你 bundle 的 push 证书。 具体的证书制作请参考这里
2、 Capabilities 中打开 Push Notifications 开关在 XCode7 中这里的开关不打开,推送也是可以正常使用的,但是在 XCode8 中,这里的开关必须要打开,不然会报错:
Error Domain=NSCocoaErrorDomain Code=3000 "未找到应用程序的“aps-environment”的授权字符串" UserInfo={NSLocalizedDescription=未找到应用程序的“aps-environment”的授权字符串}
权限申请
在使用 UserNotifications 框架的 API 的时候,首先要导入 UserNotifications 框架:
#import <UserNotifications/UserNotifications.h>
注册推送
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error)
{
NSLog(@"请求授权成功");
}
else
{
NSLog(@"请求授权失败");
}
}];
Notification settings:之前注册推送服务,用户点击了同意还是不同意,以及用户之后又做了怎样的更改我们都无从得知,现在 apple 开放了这个 API,我们可以直接获取到用户的设定信息了。注意 UNNotificationSettings 是只读对象哦,不能直接修改!只能通过以下方式获取
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
NSLog(@"%@", settings);
}];
打印
<UNNotificationSettings: 0x6000022f9dc0;
authorizationStatus: NotDetermined,
notificationCenterSetting: NotSupported,
soundSetting: NotSupported,
badgeSetting: NotSupported,
lockScreenSetting: NotSupported,
carPlaySetting: NotSupported,
criticalAlertSetting: NotSupported,
alertSetting: NotSupported,
alertStyle: None,
providesAppNotificationSettings: No>
Token Registration
[[UIApplication sharedApplication] registerForRemoteNotifications];
获取设备的Device Token
/获取DeviceToken成功
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *deviceString = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
deviceString = [deviceString stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"deviceToken:%@",deviceString);
}
//获取DeviceToken失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
NSLog(@"[DeviceToken Error]:%@\n",error.description);
}
接收推送的代理方法
// App处于前台接收通知时
// 只有app处于前台状态下才会调用,后台状态或者应用杀死下是不会调用这个方法的
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
// App通知的点击事件
// 用户点击消息才会触发
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler
苹果把本地通知跟远程通知合二为一。区分本地通知跟远程通知的类是UNPushNotificationTrigger.h 类中,UNPushNotificationTrigger 的类型是新增加的。
UNPushNotificationTrigger (远程通知) 远程推送的通知类型
UNTimeIntervalNotificationTrigger (本地通知) 一定时间之后,重复或者不重复推送通知。我们可以设置timeInterval(时间间隔)和repeats(是否重复)。
UNCalendarNotificationTrigger(本地通知) 一定日期之后,重复或者不重复推送通知 例如,你每天8点推送一个通知,只要dateComponents为8,如果你想每天8点都推送这个通知,只要repeats为YES就可以了。
UNLocationNotificationTrigger (本地通知)地理位置的一种通知,
当用户进入或离开一个地理区域来通知。
内容
以前只能展示一条文字,现在可以有 title 、subtitle 以及 body 了。
定制方法如下:
//本地通知
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = @"CALENDAR";
content.subtitle = @"Lunch";
content.body = @"Today at 12:00 PM";
content.badge = @1;
//远程推送
{
"aps" : {
"alert" : {
"title" : "CALENDAR",
"subtitle" : "Lunch",
"body" : "Today at 12:00 PM"
},
"badge" : 1
},
}
Triggers
UNTimeIntervalNotificationTrigger 定时推送
UNCalendarNotificationTrigger 定期推送
UNLocationNotificationTrigger 定点推送
//60 秒后提醒
//timeInterval:单位为秒(s) repeats:是否循环提醒
UNTimeIntervalNotificationTrigger *trigger1 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:60 repeats:NO];
// 在每周一早上 8:00 提醒
NSDateComponents *components = [[NSDateComponents alloc] init];
components.weekday = 2;
components.hour = 8;
UNCalendarNotificationTrigger *trigger3 = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES];
//首先得导入#import <CoreLocation/CoreLocation.h>,不然会regin创建有问题。
CLLocationCoordinate2D center1 = CLLocationCoordinate2DMake(31.234567, 117.4567890);
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center1 radius:500 identifier:@"桂林路"];
UNLocationNotificationTrigger *trigger4 = [UNLocationNotificationTrigger triggerWithRegion:region repeats:NO];
Add Request
NSString *requestIdentifier = @"sampleRequest";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifier
content:content
trigger:trigger1];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
}];
推送小结
整个推送的过程如下
Local Notifications 通过定义 Content 和 Trigger 向 UNUserNotificationCenter 进行 request 这三部曲来实现。
Remote Notifications 则向 APNs 发送 Notification Payload 。
Notification Handling
设定了推送,然后就结束了?iOS 10 并没有这么简单!
通过实现协议,使 App 处于前台时捕捉并处理即将触发的推送:
@interface AppDelegate () <UNUserNotificationCenterDelegate>
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
{
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound);
}
让它只显示 alert 和 sound ,而忽略 badge 。
Notification Management
彻底掌控整个推送周期:
Local Notification 通过更新 request
Remote Notification 通过新的字段 apns-collapse-id
通过之前的 addNotificationRequest: 方法,在 id 不变的情况下重新添加,就可以刷新原有的推送。
NSString *requestIdentifier = @"sampleRequest";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifier
content:newContent
trigger:newTrigger1];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
}];
删除计划的推送:
[center removePendingNotificationRequestsWithIdentifiers:@[requestIdentifier]];
此外 UNUserNotificationCenter.h 中还有诸如删除所有推送、查看已经发出的推送、删除已经发出的推送等等强大的接口。
刷新原有的推送后,在通知中心的显示里,也会有相应的变化,这里注意第 2 条信息,现在比分是 1:0
比分刷新后为 1:1,在不产生新的推送条目的情况下位置被前置了!
上面简单介绍了 iOS 10 的新框架 User Notifications Framework,了解完 iOS 10 的框架之后,还要适配iOS 8 9 系统,是不是觉得很麻烦,笔者最近发现了一款 SDK ---- MobPush,兼容 iOS 8-12 系统,接入非常简单,3行代码就可以搞定推送。
MPushNotificationConfiguration *configuration = [[MPushNotificationConfiguration alloc] init];
configuration.types = MPushAuthorizationOptionsBadge | MPushAuthorizationOptionsSound | MPushAuthorizationOptionsAlert;
[MobPush setupNotification:configuration];
同时,MobPush 支持多样化推送场景、用户分群、AB 测试、智能推送等等功能,还有完善的数据统计后台可以从多个维度实时了解 APP 和用户的使用情况