1.推送条幅和功能的变化
我们首先来看看推送消息是如何在手机上显示的
相对于iOS8,iOS9增加了输入框按钮,也就是为UIMutableUserNotificationAction增加了behavior属性
相对于iOS 9,iOS 10增加了subTitle和附件等
2.调用函数库的变化
iOS8和iOS 9使用同一套函数方法,所有的相关类声明在UIUserNotificationSettings.h和UILocalNotification.h文件中,iOS8和iOS9唯一的区别是iOS9支持输入框按钮,也就是iOS 9的UIMutableUserNotificationAction类增加了behavior和parameters属性。在iOS10中,新增了一个框架UserNotifications,提供了一套新的解决方案,所有的操作都是通过UNUserNotificationCenter执行的。
3.注册方式的变化
在这三个大的版本中,虽然注册推送的方式在不断的变化,到iOS 10甚至换了一个框架,但是推送服务的核心理念一直没变,在这里,我们可以做一个简单的划分,把注册推送服务粗略的分为下列几步:
1.创建通知分类(notificationcategory)2.创建通知设置(notificationsetting)3.注册到app
在文章开头图片上推送条幅下面还带有按钮,那么如何给推送消息添加按钮呢,这个时候就需要用到通知分类(notification category)了。我们先看两段代码:
从上面两个图可以知道,不管是在哪个版本,创建通知分类(notificationcategory)的步骤都是一样的,首先会先创建notification action,然后再添加到通知分类中。一般情况下一个通知分类中会有一到两个notification action,通过notificationaction来控制按钮的一些属性。一个通知分类最多可以有两个按钮,多余的会被忽略。
4.代理方法的变化
在用到推送服务的时候,如果不需要再推送条幅下面增加按钮,那么我们平常就只需要使用下图中的这个代理方法了
图中两个分别是本地推送和远程推送的通知,本地推送可以通过nitification这个参数获取userInfo和角标数,远程推送需要通过userInfo,这个userInfo是由应用服务器的推送消息中的Payload来决定的,一些自定义数据可以在这里获取。
而当我们需要为推送消息加一些点击事件,比如直接通过点击条幅中的回复按钮来回复聊天消息,那么在点击回复按钮之后,就会执行下图中的代理方法。
如图所示,分别是在iOS 8和iOS 9中的本地推送和远程推送的代理方法,当我们点击推送条幅中的按钮时,会调用上图中的代理方法,iOS 8和iOS 9使用的是同一套函数库,为什么我们还需要区分开来写呢。因为这个代理方法在iOS8和iOS 9中有一些区别,我们通过对比可以知道,iOS9中的方法比iOS 8多了一个参数responseInfo,那么这个参数有什么作用呢?文章开头我们说iOS9比iOS8多了一个输入框按钮,我们可以通过这个responseInfo参数获取用户在输入框中输入的字符串,通过responseInfo[UIUserNotificationActionResponseTypedTextKey]来获取。
在处理点击事件时,我们如何知道点击的按钮是哪个呢?通过对比参数identifier和定义notification action时设置的identifier,可以知道是哪个按钮。
接下来,我们看看iOS 10是如何处理这些事件的。
iOS 10新增的变化除了之前所说的那些以外,还有一个显著的变化,就是当推送消息到达时,即使你的app处于前台,仍然可以显示推送条幅。而在iOS 10之前,app必须是在后台状态才能显示。当然,即使是iOS 10,你需要达到这种效果,还需要一些配置,你需要实现上图中的第一个代理方法,并且调用completionHandler(),这样子就可以在前台收到推送条幅了。另外,上图中的第一个代理只有在app处于前台的时候才会调用。当app处于前台时,通过completionHandler()这个block来控制推送消息是以什么样的形式通知用户,一般情况下只需要像图中那样调用就可以了。
至于上图中的第二个代理,则是在点击条幅和条幅中的按钮时会被调用,这一点需要注意一下。同样的,我们要区分是哪个点击事件,和在iOS 8、iOS 9中一样,也是根据action的identifier,只不过iOS 10的这个属性没有通过参数直接暴露出来,它被封装在参数response中,可以通过response.actionIdentifier获取,当我们点击条幅(不是按钮)时,response.actionIdentifier返回的是com.apple.UNNotificationDefaultActionIdentifier。
5.iOS 10的UNNotificationRequest
在iOS 10中,如果想要创建一个本地推送,那就必须创建一个UNNotificationRequest对象,然后通过UNUserNotificationCenter发出。那么如何创建UNNotificationRequest呢,请看下图:
从上图可以看出,在iOS 10中,要创建一个UNNotificationRequest对象,一个UNNotificationRequest需要一个UNMutableNotificationContent对象用来定义推送内容和一个UNNotificaitonTrigger对象用来定义触发条件。
UNMutableNotificationContent对象除了定义body、title等一般的属性外,还可以添加附件对象UNNotificationAttachment,附件可以是图片、音频、视频,系统在执行request之前,会先验证这些附件是否必须满足下面的条件,如果不能满足,request不会被执行。
至于UNNotificaitonTrigger对象,我们一般使用它的子类,它有四种子类,分别是:
UNTimeIntervalNotificationTrigger定义距离当前时间多少秒之后触发本地推送
UNCalendarIntervalNotificationTrigger定义哪个时间点触发本地推送
UNLocationIntervalNotificationTrigger定义进入或离开一个经纬度范围时触发本地推送
UNPushIntervalNotificationTrigger当推送信息来自APNs时,request的触发器是这个类型
iOS 10的本地和远程推送的代理方法都是执行的同样的回调方法,所以需要通过判断response参数的notification.request.trigger的类型是否是UNPushIntervalNotificationTrigger,来判断是否是远程推送。
6.远程推送的附件添加
本地推送添加附件非常简单,只需要给UNNotificationRequest对象的content属性添加一个UNNotificationAttachment附件对象。但是在进行远程推送时,并不需要我们来创建UNNotificationRequest对象,这个时候我们就需要借助于UNNotificationServiceExtension对象。
UNNotificationServiceExtension有两个方法,分别是:
在第一个方法中,我们可以根据request参数重新定义一个UMMutableNotificationContent对象,这样我们就能加上一个附件了。比如我们可以让推送服务器推送一个图片url过来,然后在这个方法里面下载图片,将图片作为附件加入到UMMutableNotificationContent对象中,最后调用contentHandler这个block提交修改的内容。
执行第一个方法时,会有一定的时间限制,如果没有及时执行完方法,系统会在时间到期之前调用第二个方法,给你最后一次提交修改的机会。如果时间到期了,你还是没有提交你修改的内容(就是没有执行contentHandler这个block),系统会使用原来的那个内容。
使用这个UNNotificationServiceExtension对象时,我们不能直接使用它,需要自己创建一个它的子类,并重写它的这两个方法。具体如何创建以及使用可以参考http://www.jianshu.com/p/f77d070a8812。
最后推荐一个,好用的服务端推送工具NWPusher https://github.com/noodlewerk/NWPusher,它是使用oc编写的,可以在mac和iphone两个端运行,如果你有兴趣的话,建议读一读源码,可以帮助你了解整个推送服务的运行机制
参考链接:
http://www.jianshu.com/p/ff14939b6639
http://www.jianshu.com/p/f77d070a8812
demo:https://github.com/ZZZZou/WPushDemo