iOS 10 通知 --UserNotifications

来源:互联网 发布:淘宝上的壮阳药 编辑:程序博客网 时间:2024/06/06 02:10

前言
这里写图片描述

2016年6月,美国旧金山比尔-格雷厄姆市政礼堂,一年一度的苹果开发者盛宴 WWDC 如期举行。备受瞩目的 iOS 无疑是重头戏,而今年的 WWDC 2016 我们迎来了全新的 iOS 10 操作系统,作为苹果的主要收入来源之一的 iPhone 拥有怎样的表现,很大程度上取决于 iOS 系统的改变。 Apple 表示这是 iOS 有史以来最大的升级(our biggest release yet),更加智能开放的 Siri 、强化应用对 3D Touch 支持、 HomeKit 、电话拦截及全新设计的通知等等…

iOS 10 中将之前繁杂的推送通知统一成了 UserNotifications.framework 来集中管理和使用通知功能,还增加一些实用的功能--撤回单条通知、更新已展示通知、中途修改通知内容、在通知中显示多媒体资源、自定义UI等功能,总之非常强大(安卓早几年就有的功能��️),令(早)人(该)激(更)动(新)。

Notifications 回顾

iOS 3 - Apple 引入推送通知
iOS 4 - 引入本地通知
iOS 5 - 有了通知中心
iOS 6 - 通知中心与iCloud同步
iOS 7 - 后台静默推送
iOS 8 - 重新设置了通知权限,可交互通知
iOS 9 - 支持在通知中回复消息,Provider API 等等
从上面的更新步伐来看,Apple 对通知优化以及强化从未停止过,几乎每个 iOS 版本的更新都多多少少对消息通知进行了更新。但是频繁的更新也带来了副作用,繁杂的调用方式、复杂的接口API、不同版本的兼容等等,给开发者带来了不少麻烦。在 iOS 10 中Apple对推送通知模块进行了大规模的重构,提供了一个单独的 Framework,通知不再区分类型,易用性大大提高。

推送通知是可以有效的提高用户活跃度的一种手段,记得之前公司的App每当推送通知之后的一个小时,App 的活跃度是全天最高的时候��,往往这也是它们全天唯一的一次打开App��。 

iOS 10 UserNotifications 展示

话不多说,先看东西。

UserNotifications 实现

⚠️:以下代码运行环境为 iOS10.0 Beta6, Xcode 8.0 Beta6。

在 iOS 10 之前,推送通知分为本地推送、远程推送和静默推送。在 iOS 10 中将推送通知进行统一,远程推送系统会自动处理,如果想推送一条本地通知,需要满足三个条件:触发条件、通知内容和推送请求。所以需要处理的主要是:推送触发条件 UNNotificationTrigger 、推送附带文件 UNNotificationAttachment、推送响应事件 UNNotificationAction,Apple 还为 UserNotifications 提供了两个重要了 Extension ,开发者可以用来对推送通知进行内容扩展和服务扩展。

如何发一个通知

1⃣️ 导入头文件

#import <UserNotifications/UserNotifications.h>

2⃣️ 获取权限

// 创建通知中心 UNUserNotificationCenterUNUserNotificationCenter *notificationCenter = [UNUserNotificationCenter currentNotificationCenter];// 获取通知权限[notificationCenter requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {    if (granted) {        // 用户允许通知    } else{        NSLog(@"注册失败");    }}];// 可以通过 getNotificationSettingsWithCompletionHandler 获取权限设置[notificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {    NSLog(@"setting - %@", settings);}];

3⃣️ 远程推送设置
用户允许权限之后就可以本地推送了,如果想要接收远程推送的话还需要获取 DeviceToken ,服务器通过 DeviceToken 来完成 APNs。

// 获取 token[[UIApplication sharedApplication] registerForRemoteNotifications];// 需要在 AppDelegate 中实现下面两个 delegate// 获取成功- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {    NSLog(@"token - %@", [[NSString alloc] initWithData:deviceToken encoding:NSUTF8StringEncoding]);}// 获取失败- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {    NSLog(@"error - %@", error);}

4⃣️ 发送

本地推送

// 设置触发条件 UNNotificationTrigger (您有5秒的装X时间��)UNTimeIntervalNotificationTrigger *timeTrigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5.0f repeats:NO]; // 创建通知内容 UNMutableNotificationContentUNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];content.title = @"时间提醒";content.subtitle = @"装X时间";content.body = @"您的装X时间所剩不多请到服务台续费!";content.badge = @666;// 创建通知标示NSString *requestIdentifier = @"zhuangbility.time.of.tony";// 创建通知请求 UNNotificationRequest 将触发条件和通知内容添加到请求中UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifier content:content trigger:timeTrigger];// 将通知请求 add 到 UNUserNotificationCenter[notificationCenter addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {    if (!error) {        NSLog(@"推送已添加成功 %@", requestIdentifier);    }}];

5,4,3,2,1 … ��

远程推送

// 通过 APNs 推送 payload {    "aps" : {           "alert" : {             "title" : "Introduction to Notifications",            "subtitle" : "Session 707",            "body" : "Woah! These new notifications look amazing! Don’t you agree?"                },        "badge" : 1,        "sound" : "default"    }}

5⃣️更新和取消

取消未展示的推送

// 通过 requestIdentifier 数组来找到相应的通知进行取消[notificationCenter removePendingNotificationRequestsWithIdentifiers:@[requestIdentifier]];

取消已展示的推送

// 通过 requestIdentifier 数组来找到相应的通知进行取消[notificationCenter removeDeliveredNotificationsWithIdentifiers:@[requestIdentifier]];

更新

// 无论显示还是未显示的通知想要更新只需要新建一个 UNNotificationRequest 将 requestIdentifier 设置成想替换的通知标识就可以完成替换

看上去是不是很整洁很优雅,整个过程一气呵成,不用再区分各种推送类型 ��。

详细介绍

关于 UNUserNotificationCenter

// 创建 NotificationCenterUNUserNotificationCenter *notificationCenter = [UNUserNotificationCenter currentNotificationCenter];// 添加通知请求[notificationCenter addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {    if (!error) {        NSLog(@"推送已添加成功 %@", requestIdentifier);    }}];

iOS 10 的通知中心 UNUserNotificationCenter 提供了两个代理函数,来实现通知前台显示和通知交互处理。

// 引入 delegate<UNUserNotificationCenterDelegate>// 设置 delegatenotificationCenter.delegate = self;// 如果想让通知在前台显示// * center 返回的通知中心    // * notification 返回的通知(可以获取到显示通知的时间和 UNNotificationRequest) // * completionHandler 如果想让通知再前台的时候显示需要实现 如果不想显示某条通知的话可以设置成 completionHandler(0)- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler;// 通知有交互时会回调这个 delegate// * center 返回的通知中心// * response 回调相应(可以获取到 notification 附带的信息和 actionIdentifier 交互标识)// * completionHandler 交互完成之后处理// ⚠️ 这个回调 applicationDidFinishLaunching: 执行之后才有效- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler;

关于通知权限

UNAuthorizationOptionBadge 允许设置角标
UNAuthorizationOptionSound 允许推送声音
UNAuthorizationOptionAlert 允许弹窗
UNAuthorizationOptionCarPlay 允许carpay(并没有车��)
关于 UNNotificationTrigger 推送触发器

首先说推送触发条件,在用户日常生活中会有很多种情形需要通知,比如:新闻提醒、定时吃药、定期体检、到达某个地方提醒用户等等,这些功能在 UserNotifications 中都提供了相应的接口。

Apple 为开发者提供了 UNNotificationTrigger 触发条件基类,需要通过子类实现具体功能:

UNPushNotificationTrigger 通过 APNs 服务发来的推送自动创建
UNTimeIntervalNotificationTrigger 定时触发
UNCalendarNotificationTrigger 定期触发
UNLocationNotificationTrigger 定位触发
代码:

// 远程推送// 由系统自动创建,Apple 没有开放相应的接口UNPushNotificationTrigger// 定时推送// interval 时间间隔 repeats 是否重复 ⚠️ 如果要是 YES 的话时间间隔必须大于 60 秒UNTimeIntervalNotificationTrigger *timeTrigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5.0f repeats:NO];// 定期推送// 创建日期组建NSDateComponents *components = [[NSDateComponents alloc] init];components.weekday = 2;components.hour = 8;// components 日期 repeats 是否重复UNCalendarNotificationTrigger *calendarTrigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES];// 定点推送// 创建位置信息CLRegion *region = [[CLRegion alloc] init];// region 位置信息 repeats 是否重复 (CLRegion 可以是地理位置信息)UNLocationNotificationTrigger *locationTrigger = [UNLocationNotificationTrigger triggerWithRegion:region repeats:NO];

关于通知内容 UNMutableNotificationContent

// UNNotificationContent 的属性都是 readonly 的,所以必须要用 UNMutableNotificationContent// 创建通知内容UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];// 通知显示的标题content.title = @"This is title";// 通知的副标题content.subtitle = @"This is subtitle";// 通知的内容 ⚠️上面两个属性可以不设置或者设置为空字符串,但是如果body这样操作通知将不显示content.body = @"i am body!";// 应用角标 NSNumber 类型content.badge = @666;// 收到通知时的声音content.sound = [UNNotificationSound defaultSound];// 通知附带信息content.userInfo = @{@"name":@"tony"};// 线程标识符可用户通知分组content.threadIdentifier = @"";// 用户从通知中心打开 App (具体使用方法待研究)content.launchImageName = @"image";// 下面两个属性后面会具体介绍怎么使用// 通知附件可以传多个但是只会显示第一个 content.attachments = @[attachment];// 类别标识符,用于有交互的通知content.categoryIdentifier = @"category";

关于 UNNotificationRequest

// 创建一个通知请求// * identifier 通知请求标识符,用于区分通知请求// ⚠️⚠️:这里一定要设置成有值的字符串,设置成 nil 的话 APP 会崩溃,设置成空字符串的话整个桌面应用(Launchpad.app)会崩溃,也就是手机死机不断重启或模拟器死机,必须刷机才能恢复,亲测必现��请谨慎测试。// * content 通知内容// * trigger 触发器UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"zhuangbility.time.of.tony" content:content trigger:trigger];

如何优雅的通知

多媒体附件推送通知 UNNotificationAttachment

新的通知框架中为开发者提供了丰富的接口,其中就包括附件通知(图片、gif、音频、视频)。不过对图片和视频的大小做了一些限制(图片不能超过 5M,视频不能超过 50M),而且附件资源必须存在本地,如果是远程推送的网络资源需要提前下载到本地(稍后介绍如何使用)。

// 资源路径NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"video" withExtension:@"mp4"];// 创建附件资源    // * identifier 资源标识符// * URL 资源路径// * options 资源可选操作 比如隐藏缩略图之类的// * error 异常处理UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"video.attachment" URL:videoURL options:nil error:&error];// 将附件资源添加到 UNMutableNotificationContent 中content.attachments = @[attachment];

这里写图片描述

支持的附件资源的格式详情参见:Apple

Apple 还为 UserNotifications 提供了两个强大的 Extension 用于扩展推送服务和自定义通知视图。

推送通知服务扩展 UNNotificationServiceExtension

上面说到远程附件推送附带网络资源的问题,通过 UNNotificationServiceExtension 可以实现远程推送通知的内容进行截取并修改,这样就可以实现远程推送过来的网络资源提前下载,然后通过 Attachment 展示了。

新建一个 ServiceExtension
这里写图片描述

新建完成可以看到项目工程中多了一个文件夹、三个文件和 新的target

这里写图片描述

如果想真机调试的话需要在开发者后台重新创建一个 App ID 和 描述文件,推荐使用通配类型。

远程推送 payload

{     aps: {         alert: {            "title" : "title is me",            "subtitle" : "i am subtitle",            "body" : "Woah! These new notifications look amazing! Don’t you agree?"        },         mutable-content: 1     }     my-attachment: "https://example.com/photo.jpg" }

mutable-content 表示接到通知后需要修改,传 1 系统会自动走 ServiceExtension 处理。my-attachment 资源地址,⚠️:一定要是 https 的资源,否则无法展示。Extension Bundle 和 Main Bundle 是不同的目录 在 Extension 目录中访问 Main Bundle

直接在 Xcode 生成的 .m 文件中编辑

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {    self.contentHandler = contentHandler;    self.bestAttemptContent = [request.content mutableCopy];    // Modify the notification content here...    // 设置截取到的通知的 title    self.bestAttemptContent.title = [NSString stringWithFormat:@"%@", appDisplayName];    // 下载推送过来的资源,并保存到本地    [self downloadAndSaveWithURL:self.bestAttemptContent.userInfo[@"my-attachment"] callBack:^(NSURL *filePath) {        // 创建附件元素        NSError *error = nil;        UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"image.attachment" URL:filePath options:nil error:&error];        self.bestAttemptContent.attachments = @[attachment];        self.bestAttemptContent.body = [NSString stringWithFormat:@"%@", filePath];        // 设置推送回调,将修改完的通知内容传进去        self.contentHandler(self.bestAttemptContent);    }];}

虽然给了开发者处理推送通知的权限,但是也不是完全没有限制的,只有 30 秒的处理时间,所以推送多附件资源的时候要考虑文件的大小。

通知拦截还有一个可能就是加密推送,服务端推送加密信息客户端截取、解密、展示。��

推送通知内容扩展 UNNotificationContentExtension 自定义推送视图

新建一个 ContentExtension
这里写图片描述

新建完成可以看到项目工程中多了一个文件夹、四个个文件和 新的 target
这里写图片描述

新的文件夹中,直接可以在 ViewController 上进行 UI 的编写,也可以只用 storyboard 进行可视化编辑。

// 接收到通知获取内容对 UI 进行更新- (void)didReceiveNotification:(UNNotification *)notification {}

准备好自定义的视图 UI 之后,在 info.plist 中对 UNNotificationExtensionCategory 添加一个标识符,系统可以通过标识符找 到对应的自定义视图

这里写图片描述

本地推送:

UNMutableNotificationContent *customUIContent = [[UNMutableNotificationContent alloc] init]; customUIContent.title = ...;customUIContent.body = ...;customUIContent.categoryIdentifier = @"content.cat";...

远程推送 payload

{    "aps" : {        "alert" : {            "title" : "title",            "body" : "Your message Here"        },        "mutable-content" : "1", "category" : "content.cat"    },    attachment : "http://....jpg"}

category 自定义视图的标识符。

如果在自定义视图的推送通知中如果存在可交互的控件怎么处理?good question,系统本身不支持自定义视图的交互,但 是通过 UNNotificationAction 可以完成类似的效果,接下来的一节会介绍关于通知中涉及到的交互操作。

通知交互 UNNotificationAction

从上面的回顾可以知晓,早在 iOS 8 中就已经提供了通知的交互相应接口,在 iOS 9 中得道扩展。Apple 提供了一个 category 专门负责通知中的交互,开发者需要做的就是注册一个 category 进行设置。

普通点击交互 UNNotificationAction

// 创建两个 UNNotificationAction// * identifier 交互标识符  // * title 按钮标题// * options 交互选项 枚举类型 UNNotificationActionOptionAuthenticationRequired 执行前需要解锁 NNotificationActionOptionDestructive 点击后消失 UNNotificationActionOptionForeground 前台之行UNNotificationAction *goodByeAction = [UNNotificationAction actionWithIdentifier:@"action.sayhi" title:@"你好" options:UNNotificationActionOptionForeground];UNNotificationAction *cancelAction = [UNNotificationAction actionWithIdentifier:@"action.cancel" title:@"取消" options:UNNotificationActionOptionDestructive];// 注册 category// * identifier 标识符// * actions 操作数组// * intentIdentifiers 意图标识符 可在 <Intents/INIntentIdentifiers.h> 中查看,蛀牙是针对电话、carplay 等开放的 API。   // * options 通知选项 枚举类型 也是为了支持 carplayUNNotificationCategory *notificationCategory = [UNNotificationCategory categoryWithIdentifier:@"category.action" actions:@[goodByeAction, cancelAction] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];

这里写图片描述
文本输入 UNTextInputNotificationAction

// 创建 UNTextInputNotificationAction 比 UNNotificationAction 多了两个参数// * buttonTitle 输入框右边的按钮标题// * placeholder 输入框占位符UNTextInputNotificationAction *inputAction = [UNTextInputNotificationAction actionWithIdentifier:@"action.input" title:@"输入" options:UNNotificationActionOptionForeground textInputButtonTitle:@"发送" textInputPlaceholder:@"告诉我"];// 注册 categoryUNNotificationCategory *notificationCategory = [UNNotificationCategory categoryWithIdentifier:@"category.custom" actions:@[inputAction] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];

这里写图片描述

本地推送

只需要将 UNMutableNotificationContent 的 categoryIdentifier 设置成定义好的 identifier 就可以了。

远程推送 payload

// 将 category 添加到通知中心[notificationCenter setNotificationCategories:[NSSet setWithObject:notificationCategory]];// category 预先设置好的标识符。{    "aps" : {        ...        "category" : "category.action",         ...    }, }

结合 ContentExtension

UNNotificationCategory 和 UNNotificationExtensionCategory 设置成同一个标识符就可以完成自定义视图通知可交互。

// 在 ContentExtension 中实现该方法可以对交互进行处理// * response 交互通知响应者 可获得用户所输入的内容// * completion 交互回调 UNNotificationContentExtensionResponseOptionDoNotDismiss 交互后通知不消失 UNNotificationContentExtensionResponseOptionDismiss 交互后消失 UNNotificationContentExtensionResponseOptionDismissAndForwardAction 消失并传递事件给 UNUserNotificationCenterDelegate - (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^) (UNNotificationContentExtensionResponseOption))completion {    UNTextInputNotificationResponse *inputResponse = (UNTextInputNotificationResponse *)response;     self.label.text = inputResponse.userText;     completion(UNNotificationContentExtensionResponseOptionDoNotDismiss);}

这里写图片描述

总结

在 iOS 10 beta 发布之后,第一时间安装到手机上并进行了一番体验,总体下来感觉,iOS 10 是自 iOS 7 以来最大的一次更新,整个系统 的更新非常的全面。新事物的产生必定是旧事物的淘汰换来的,iOS 10 中废弃的 API:

UILocalNotification
UIMutableUserNotificationAction
UIMutableUserNotificationCategory
UIUserNotificationAction
UIUserNotificationCategory
UIUserNotificationSettings
handleActionWithIdentifier:forLocalNotification:
handleActionWithIdentifier:forRemoteNotification:
didReceiveLocalNotification:withCompletion:
didReceiveRemoteNotification:withCompletion:
尝试实现了 UserNotifications 的一些方法,发现确实强大了不少同时也简单了不少,少了很多复杂而有难以捉摸的操作。多媒体附件推送、通知拦截修改、自定义通知视图都给产品经理和开发者们不少的可能性,从而丰富自己的应用。

转载至 http://qoofan.com/read/PnEaMEZonD.html

0 0