iOS推送之远程推送

506 查看

最近公司项目升级重构(重写),除了本来我所负责的模块,最后临危受命接了推送(远程和本地)相关的模块,顺便把推送的相关知识复习了一遍。后期连续工作十几天加上最后一天的通(瞎)宵(熬)达(一)旦(夜),也算是不辱使命。此文除了讲解远程推送相关的基本知识外,也会涉及一些推送相关的奇淫技巧。另外本文主要讲解远程推送,后续会出一篇iOS推送之本地推送(iOS Notification Of Local Notification)的姊妹篇。

此篇文章的逻辑如下图所示:

 
图0-0 此篇文章的逻辑图

远程推送原理

学习一些东西前我认为最好能了解它的原理,这样以后我们遇到问题的时候,就可以很快速的找到错误之所在,如果对原理不感兴趣的同学可直接下翻到应用部分【远程推送应用】。

iOS app大多数都是基于client/server模式开发的,client就是安装在我们设备上的app,server就是远程服务器,主要给我们的app提供数据,因为也被称为Provider。那么问题来了,当App处于Terminate状态的时候,当client与server断开的时候,client如何与server进行通信呢?是的,这时候Remote Notifications很好的解决了这个困境。苹果所提供的一套服务称之为Apple Push Notification service,就是我们所谓的APNs。

推送消息传输路径: Provider-APNs-Client App

我们的设备联网时(无论是蜂窝联网还是Wi-Fi联网)都会与苹果的APNs服务器建立一个长连接(persistent IP connection),当Provider推送一条通知的时候,这条通知并不是直接推送给了我们的设备,而是先推送到苹果的APNs服务器上面,而苹果的APNs服务器再通过与设备建立的长连接进而把通知推送到我们的设备上(参考图1-1,图1-2)。而当设备处于非联网状态的时候,APNs服务器会保留Provider所推送的最后一条通知,当设备转换为连网状态时,APNs则把其保留的最后一条通知推送给我们的设备;如果设备长时间处于非联网状态下,那么APNs服务器为其保存的最后一条通知也会丢失。Remote Notification必须要求设备连网状态下才能收到,并且太频繁的接收远程推送通知对设备的电池寿命是有一定的影响的。

 
图1-1 Pushing a remote notification from a provider to a client app
 
图1-2 Pushing remote notifications from multiple providers to multiple devices

deviceToken的生成

当一个App注册接收远程通知时,系统会发送请求到APNs服务器,APNs服务器收到此请求会根据请求所带的key值生成一个独一无二的value值也就是所谓的deviceToken,而后APNs服务器会把此deviceToken包装成一个NSData对象发送到对应请求的App上。然后App把此deviceToken发送给我们自己的服务器,就是所谓的Provider。Provider收到deviceToken以后进行储存等相关处理,以后Provider给我们的设备推送通知的时候,必须包含此deviceToken。(参考图1-3,图1-4)

 
图1-3 Managing the device token
 
图1-4 Sharing the device token

这个时候你可能会问deviceToken到底是什么?有什么用?为什么是独一无二的?

  • 是什么:deviceToken其实就是根据注册远程通知的时候向APNs服务器发送的Token key,Token key中包含了设备的UDID和App的Bundle Identifier,然后苹果APNs服务器根据此Token key编码生成一个deviceToken。deviceToken可以简单理解为就是包含了设备信息和应用信息的一串编码。
  • 有什么用:上面提到Provider推送消息的时候必须带有此deviceToken,然后此消息就根据deviceToken(UDID + App’s Bundle Identifier)找到对应的设备以及该设备上对应的应用,从而把此推送消息推送给此应用。
  • 唯一性:苹果APNs的编码技术和deviceToken的独特作用保证了他的唯一性。唯一性并不是说一台设备上的一个应用程序永远只有一个deviceToken,当用户升级系统的时候deviceToken是会变化的。

远程推送应用

注册远程通知(获取deviceToken)

注册远程通知的方法

一般都是在App启动完成的时候去注册远程通知注册方法调用一般都在didFinishLaunchingWithOptions:方法中

处理注册远程通知的回调方法

在iOS8之后增加了可操作通知类型,可操作通知允许开发者添加自定义跳转事件。这些高级功能此篇文章不讲解,有兴趣的同学可自己去了解UIUserNotificationAction UIMutableUserNotificationAction UIUserNotificationCategory UIMutableUserNotificationCategory这几个类。

处理接收到远程通知消息(会回调以下方法中的某一个)

application: didFinishLaunchingWithOptions:

此方法在程序第一次启动是调用,也就是说App从Terminate状态进入Foreground状态的时候,根据方法内代码判断是否有推送消息。

application: didReceiveRemoteNotification:

如果App处于Background状态时,只用用户点击了通知消息时才会调用该方法;如果App处于Foreground状态,会直接调用该方法。

application: didReceiveRemoteNotification: fetchCompletionHandler:

iOS7之前苹果是不支持多任务的,这也是iOS系统对硬件要求低,流畅性好的原因之一。iOS7之后,苹果开始支持多任务,即App可在后台做一些更新UI、下载数据的操作等。若要接收到远程推送的时候要在后台做一些事情则需要把后台远程推送模式打开。不适配iOS7之前系统的项目建议使用此后台模式,充分利用苹果推出的多任务模式,不枉费苹果的一片苦心啊!设置后台模式方法项目对应TARGETS-Capabilities-Background Modes-Remote Notifications具体设置方法如下图(图2-1)。

 
图2-1 Setting App Background Modes

此方法不论App处于Foreground状态还是处于Background状态,收到远程推送消息的时候都会立即调用此方法。此方法需要配置后台模式并且在推送负载中必须有content-available此key值,对应的value值为1(详细介绍参考下面【远程通知负载内容】)。