最近在作基于环信的及时通信项目,项目中必不可少的用到了远程推送功能,在我解决推送问题的过程当中遇到了一些坑,同时也得到了很多的经验. 在我的理解以及查阅资料的基础上将远程推送相关的知识总结以下:php
在码代码时咱们不该该只看到屏幕,还应该看到屏幕后面的东西. 为了更好的理解远程推送,首先咱们须要了解其原理.html
iOS app大多都是基于C/S模式开发的,也就是 客户端/服务器模式,客户端也就是咱们用来安装app的手机,服务器是为客户端提供数据用的.由于也被称为Provider . 这种模式存在一个问题,那就是当app处理Terminate状态时,二者之间是没法进行通信的.为了解决这个问题 苹果所提供的一套服务称之为Apple Push Notification service,就是咱们所谓的APNs。服务器
咱们的设备联网时(不管是蜂窝联网仍是Wi-Fi联网)都会与苹果的APNs服务器创建一个长链接(persistent IP connection),当Provider推送一条通知的时候,这条通知并非直接推送给了咱们的设备,而是先推送到苹果的APNs服务器上面,而苹果的APNs服务器再经过与设备创建的长链接进而把通知推送到咱们的设备上。而当设备处于非联网状态的时候,APNs服务器会保留Provider所推送的最后一条通知,当设备转换为连网状态时,APNs则把其保留的最后一条通知推送给咱们的设备;若是设备长时间处于非联网状态下,那么APNs服务器为其保存的最后一条通知也会丢失。Remote Notification必需要求设备连网状态下才能收到。app
2.deviceToken的生成ide
当一个App注册接收远程通知时,系统会发送请求到APNs服务器,APNs服务器收到此请求会根据请求所带的key值生成一个独一无二的value值,也就是所谓的deviceToken,然后APNs服务器会把此deviceToken包装成一个NSData对象发送到对应请求的App上。而后App把此deviceToken发送给咱们本身的服务器,就是所谓的Provider。Provider收到deviceToken之后进行储存等相关处理,之后Provider给咱们的设备推送通知的时候,必须包含此deviceToken。fetch
这个时候你可能会问deviceToken究竟是什么?有什么用?为何是独一无二的?ui
// 这里咱们用的是极光推送 编码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { //能够添加自定义categories [APService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; } else { //categories 必须为nil [APService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) categories:nil]; } }
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // Required [APService registerDeviceToken:deviceToken]; }
-(void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
在上面的两个方法中处理收到的远程推送消息spa
当App收到远程推送消息时,app不会有任何回调 ,只有用户手动点击通知栏里的通知(或者是收到通知时的弹窗)才会触发以上两个回调方法 .code
须要注意的是:若是当app处于前台时收到了远程推送通知,也会调用第二个方法,可是不会显示通知,所以在这个方法里须要咱们判断程序是处于后台仍是前台,并选择是否对通知进行处理.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{ //在这里须要判断是否在前台 UIApplicationState state = [[UIApplication sharedApplication] applicationState]; if (state == UIApplicationStateActive) {// 程序在前台 // ... } else { // 程序在后台经过点击通知消息唤醒 // } }
iOS7以前苹果是不持之多任务的,iOS7以后开始支持多任务即App可在后台作一些更新UI、下载数据的操做等。若要接收到远程推送的时候要在后台作一些事情则须要把后台远程推送模式打开。
设置后台模式方法项目对应TARGETS-Capabilities-Background Modes-Remote Notifications具体设置方法以下图
此方法不论App处于前台仍是后台状态,收到远程推送消息的时候都会当即调用此方法。此方法须要配置后台模式而且在推送负载中必须有content-available此key值,对应的value值为1.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // 在此方法中必定要调用completionHandler这个回调,告诉系统是否处理成功 UIBackgroundFetchResultNewData, // 成功接收到数据 UIBackgroundFetchResultNoData, // 没有接收到数据 UIBackgroundFetchResultFailed // 接受失败 if (userInfo) { completionHandler(UIBackgroundFetchResultNewData); } else { completionHandler(UIBackgroundFetchResultNoData); } }
远程通知负载的大小根据Provider使用的API不一样而不一样。当使用HTTP/2 provider API时,负载最大为4096bytes,即4kB;当使用legacy binary interface时,负载最大为2048bytes,即2kB。当负载大小超过规定的负载大小时,APNs会拒绝发送此消息。
每一条通知的消息都会组成一个JSON字典对象,其格式以下所示,示例中的key值为苹果官方所用key。自定义字段的时候注意必定要避开这些key值。
{ "aps" : { "alert" : { // string or dictionary "title" : "string" "body" : "string", "title-loc-key" : "string or null" "title-loc-args" : "array of strings or null" "action-loc-key" : "string or null" "loc-key" : "string" "loc-args" : "array of strings" "launch-image" : "string" }, "badge" : number, "sound" : "string" "content-available" : number; "category" : "string" }, } aps:推送消息必须有的key alert:推送消息包含此key值,系统就会根据用户的设置展现标准的推送信息 badge:在app图标上显示消息数量,缺乏此key值,消息数量就不会改变,消除标记时把此key对应的value设置为0 sound:设置推送声音的key值,系统默认提示声音对应的value值为default content-available:此key值设置为1,系统接收到推送消息时就会调用不一样的回调方法,iOS7以后配置后台模式 category:UIMutableUserNotificationCategory's identifier 可操做通知类型的key值 title:简短描述此调推送消息的目的,适用系统iOS8.2以后版本 body:推送的内容 title-loc-key:功能相似title,附加功能是国际化,适用系统iOS8.2以后版本 title-loc-args:配合title-loc-key字段使用,适用系统iOS8.2以后版本 action-loc-key:可操做通知类型key值,不详细叙述 loc-key:参考title-loc-key loc-args:参考title-loc-args launch-image:点击推送消息或者移动事件滑块时,显示的图片。若是缺乏此key值,会加载app默认的启动图片。
固然以上key值并非每条推送消息都必带的key值,应当根据需求来选择所须要的key值,除了以上系统所提供的key值外,你还能够自定义本身的key值,来做为消息推送的负载,自定义key值与aps此key值并列。以下格式:
{ "aps" : { "alert" : "您有一条新的好友推荐", "badge" : 2, "sound" : "happy" }, "Id" : 222, // 自定义key值 "type" : "myType" // 自定义key值 }
推送是为了把咱们好的资源以及最精彩内容 推送给用户,熟练而且恰当的使用APNs能够及时通知用户最新动态,提升app的活跃用户量.此次对远程推送的研究让我对它的运用更加熟练了.
内容若是纰漏,欢迎指正.
参考:
http://www.jianshu.com/p/4b947569a548
http://www.cocoachina.com/bbs/read.php?tid-290239-uid-441468-page-1.html