iOS10推出之后,苹果对推送通知模块进行了比较彻底的重构,展现形态上,新的推送通知要要丰富很多,支持标题,子标题,内容,多媒体,另外也支持用交互,代码层面,推送通知统一由UserNotifications FrameWork
管理,统一了本地通知与远程通知的概念,统一了通知处理的回调入口,对于开发者来说是一大快事。
不过,现阶段我们肯定不能只用ios10 的新推送特性,所以未来一段时间,我们的代码里面可能需要两套推送通知的代码,根据系统的版本区分调用
请求权限
推送的所有操作都统一由UNUserNotificationCenter
来处理
开始之前需要先导入#import <UserNotifications/UserNotifications.h>
请求推送通知权限
这里只是向用户请求推送通知的权限,如果用户允许,那么我们可以发送处理通知(本地通知以及远程通知),但是如果我们想发送远程通知,还必须要拿到token,这一步的注册并不包含拿token的注册,如果我们只调用了下面的方法,是不会进入token的回调的
1 | [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound completionHandler:^(BOOL granted, NSError * _Nullable error) { |
请求token
在ios10上请求获取token还是用的原来的方法,调用该方法后,会收到获取token成功或者失败的回调
1 | [[UIApplication sharedApplication] registerForRemoteNotifications]; |
获取用户Notification的配置
我们可以获取用户对Notification的配置,包括,是否允许通知,开启通知的哪些功能等等
1 | [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { |
新的通知
ios10对本地通知以及远程通知进行了统一,所以不论是本地通知,还是远程通知,我们拿到的对象都是一致的,接收到通知的处理流程也是一致的
不同的是本地通知我们是用代码构建的,远程通知是拼Json数据构建的
UNNotificationContent
新的通知内容对象,包括了一个推送通知内容方面的所有定制
1 | //附件,图片,音频,等 |
对比原来的推送内容,增加了title,subtitle,多媒体attachment支持等等。
UNNotificationAttachment
表示一个多媒体类型附件,目前测试支持图片,音频,视频
必须使用本地资源,如果资源文件名字包含扩展名,那么不需要显示的指定文件类型,如果资源文件没有扩展名,那么需要通过option的UNNotificationAttachmentOptionsTypeHintKey
key指定资源的**UTI**
类型,否则会创建失败
1 | //图片 路径不指定类型,通过option指定UTI类型 |
注意,这种代码创建的方式只适用于本地通知,如果远程通知我们也想添加Attachment,那么必须依赖Notification Service Extension,原理是在远程通知显示之前,修改通知的UNNotificationContent对象,然后为其添加Attachment,后面会讲到
UserInfo
其中userInfo
对象,在本地通知的时候由我们创建并填入自定义信息。
在远程通知的时候,是推送通知的整个json字符串的Dictionary对象,比如下面这种1
2
3
4
5
6
7
8
9
10
11
12{
"aps": {
"alert": {
"body": "this is body",
"title": "this is title",
},
"badge": 4,
"payload": "payload"
}
"key1":"aaaaaa",
"key2":"bbbbbb"
}
所以远程推送的时候,我们可以通过userInfo[@"key1"]
这种方式拿到我们的自定义数据
一个完整的content对象
下面构建一个推送通知内容对象
1 | UNMutableNotificationContent *content=[[UNMutableNotificationContent alloc]init]; |
通过上面的代码创建了一个content对象,设置了title,subTitle,body,以及一张图片,需要注意的是图片必须使用本地资源,并且必须携带后缀名,如果没有携带后缀名,需要在
option里面通过UNNotificationAttachmentOptionsTypeHintKey
key指定类型
Trigger触发器
本地推送通知需要设置一个触发器,当触发器满足条件的时候,发起本地推送,包括如下三种
1 | //时间触发器 |
创建触发器
1 | //5秒以后触发,不重复 |
推送请求
这里面有点像网络编程的概念,上面创建了content,trigger,需要用其创建一个request,其中比较重要的是identifier属性,我们可以通过这个标识符来取消,更新未发送的通知
1 | NSString *identifider=@"notification1"; |
添加请求
请求创建完毕需要添加到队列,发送请求,这样,一个本地通知就创建完成,等待触发时机进行推送
1 | [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { |
推送通知的生命周期
查询,更新,删除
当我们把一个推送通知request添加到UNUserNotificationCenter
之后,就会等待其触发,现在iOS10之后,在其触发之前,或者触发之后,我们可以对其进行如下一系列操作。
- 获取挂起的所有通知请求
- 删除挂起的请求(使用标识符),这样改请求就不会再触发
- 删除所有挂起的请求
- 获取已经送达的通知(没有被用户点击,仍然保存在通知中心列表的所有通知)
- 删除已经送达的通知(使用标识符)
- 删除已经送达的所有通知
- 更新上面的通知,也会直接反应到系统的通知中心
1 | //挂起的通知操作 |
接收回调
不同于之前的ios版本,把本地通知,远程通知,点击通知的,处理入口分散到各个地方,ios10将所有通知的处理回调统一起来,主要集中在UNUserNotificationCenter
的delegate的两个函数
1 | //当应用在前台的时候,收到推送通知,在展示之前会进入这个方法,我们通过设定options来决定如何展示这条通知,可以是只展示badge,sound,alert,也可都展示 |
在ios10以前,当应用在前台的时候,即使收到通知,也不会展示在顶部,如果想展示我们只能自己实现UI,在ios10以后,当应用在前台的时候,我们只需要实现willPresentNotification
方法,就能决定是否展示这个通知。当然我们可以根据通知的content做决定
当用户点击通知的时候,无论是本地通知,还是远程通知,无论应用是打开还是关闭,肯定会进入didReceiveNotificationResponse方法,我们可以在这里进行统一的处理
远程推送
远程推送需要服务端构建推送json结构,下面是一个不带任何多媒体信息的推送结构
1 | { |
如果我们想要发送一个远程通知,并且携带多媒体信息,我们需要在aps里面增加mutable-content : 1
,用来表示这个推送的content是可以被修改的,这样,当我们为app创建了notification service extension之后,会进入notification service extension
的回调方法,在里面,我们可以在远程通知展示之前,对其content进行修改。
依照这个原理,我们需要构建如下json1
2
3
4
5
6
7
8
9
10
11
12
13{
"aps": {
"alert": {
"body": "this is body",
"title": "this is title",
"subtitle":"this is subtitle"
},
"badge": 4,
"mutable-content" : 1
}
"image":"http://www.xxxx.xxx/xxxxxx.jpg",
"key2":"bbbbbb"
}
然后在notification service extension
的回调方法里面通过userInfo获取image,进行下载,然后用下载的本地文件创建attachment,最后赋值给content,即可完成对远程通知的修改。这样就能展示多媒体内容
Notification Service Extension
Notification Service Extension
是一个app extension,是一段嵌入宿主app的二进制文件。
Notification Service Extension
允许我们在收到远程推送并且在其展示之前,对推送的内容进行修改。
首先我们要创建一个Notification Service Extension
target
其中Embed in Application
是我们Notification Service Extension
需要嵌入的程序,也就是说,我们只对这个application起作用
创建好Notification Service Extension
之后,系统会自动为我们创建如下文件
其中主要包含两个方法
1 | //收到远程通知,在展示之前会进入这个方法。这里允许我们创建一个新的content对象,返回给contentHandler,用来展示 |
下面的代码是一个展示图片的Notification Service Extension
代码示例
1 | - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler { |
Notification Service Extension
其实也是一个独立的二进制文件,也有info.plist配置文件,也有对应的bundleId,同样需要用证书签名,需要对应的mobileprovision配置文件。
打开编译好的app包,发现里面多了Plugins文件夹子,里面正式这个app所有的extension包
右键显示包内容,其内容与普通的app包是一样的
所以如果我们想对app重签名,必须对Plugins文件夹内的所有extension进行重签名,而对extension重签名,同样需要知道其bundleId,需要为这个bundleId创建mobileprovision配置文件
另外我们运行的时候选择extension
这个target然后从选择框里面选择embeded application,这样当我们收到推送的时候,能在didReceiveNotificationRequest
里面进行断点调试