iOS 远程推送

来源:互联网 发布:淘宝林珊珊店铺头像 编辑:程序博客网 时间:2024/06/05 00:54

JPush在iOS平台上的集成
推送原理和demo
在iOS 平台上大部分应用是不允许在后台运行并保持网络链接的,在应用没有被运行的时候,只能通过APNS服务把数据发送到终端用户。
推送过程
上图为注册推送的过程
下面是推送通知到设备应用的原理图

首先手机应用向APNS服务器申请推送服务,在注册成功后会收到苹果下发的deviceToken到设备,应用能够通过回调获得deviceToken,这个token表示设备应用的唯一id,苹果可以通过这个id找到我们的设备应用,Provider是我们自己的推送服务器,现在使用的是极光推送,就是Provider就是极光推送服务器,将deviceToken上报到极光推送服务器,当我们需要发送推送通知到我们的设备应用的时候,我们的推送服务器给APNS发送推送请求,如果这个请求被验证为合法,APNS会通过deviceToken找到指定的设备应用发送推送通知。

下面是JPush的原理图
JPush原理图
开发者可以通过自己的服务器调用JPush API给JPush服务器发送推送请求,也可以通过极光推送台JPush Web Portal给JPush API发送推送请求,JPush发送推送请求有两种方式:
一种是推送通知,推送通知会通过 APNS下发到设备应用,推送通知走的是红线,
另一种是自定义消息,走的是蓝色线路,应用在前台的时候,如果发送应用类消息到了前台会通过JPush TCP长链接下发这条消息。

推送效果演示
通过tag推送
通过alias推送
registration ID
所有设备推送

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必须要求设备连网状态下才能收到,并且太频繁的接收远程推送通知对设备的电池寿命是有一定的影响的。

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

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:方法中
- (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions {
// 在iOS8之前注册远程通知的方法,如果项目要支持iOS8以前的版本,必须要写此方法
UIRemoteNotificationType types = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;

[[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];// iOS8之后注册远程通知的方法UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];[[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];

}

处理注册远程通知的回调方法
// 注册成功回调方法,其中deviceToken即为APNs返回的token
- (void)application:(UIApplication )application didRegisterForRemoteNotificationsWithDeviceToken:(NSData )deviceToken {
[self sendProviderDeviceToken:deviceToken]; // 将此deviceToken发送给Provider
}
// 注册失败回调方法,处理失败情况
- (void)application:(UIApplication )application didFailToRegisterForRemoteNotificationsWithError:(NSError )error {

}

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

application: didFinishLaunchingWithOptions:

此方法在程序第一次启动是调用,也就是说App从Terminate状态进入Foreground状态的时候,根据方法内代码判断是否有推送消息。
- (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions {

//  userInfo为收到远程通知的内容NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];if (userInfo) {     // 有推送的消息,处理推送的消息}return YES;

}

application: didReceiveRemoteNotification:

如果App处于Background状态时,只用用户点击了通知消息时才会调用该方法;如果App处于Foreground状态,会直接调用该方法。
- (void)application:(UIApplication )application didReceiveRemoteNotification:(NSDictionary )userInfo {

}

application: didReceiveRemoteNotification: fetchCompletionHandler:

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

此方法不论App处于Foreground状态还是处于Background状态,收到远程推送消息的时候都会立即调用此方法。此方法需要配置后台模式并且在推送负载中必须有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” : “Provider push message.”,
“badge” : 9,
“sound” : “toAlice.aiff”
},
“Id” : 1314, // 自定义key值
“type” : “customType” // 自定义key值
}

指定用户的推送

对于要求用户登录的App,推送是可以指定用户的,同一条推送有些用户可以收到,但是有些用户又不能收到。说起来这个就要提到另外的一个token了,一般称之为userToken,userToken一般都是根据自己公司自定义的规则去生成的。userToken是以用户的账号加对应的密码生成的。这样结合上面提到的deviceToken,就可以做到根据不同的用户推送不同的消息。deviceToken找到对应某台设备和该设备上的应用,而userToken对应找到该用户。客户端在上报deviceToken的时候,要把userToken对应一起上报给服务端也就是Provider。

0 0