iOS远程推送

    最近在作基于环信的及时通信项目,项目中必不可少的用到了远程推送功能,在我解决推送问题的过程当中遇到了一些坑,同时也得到了很多的经验. 在我的理解以及查阅资料的基础上将远程推送相关的知识总结以下:php

一.远程推送的原理

在码代码时咱们不该该只看到屏幕,还应该看到屏幕后面的东西. 为了更好的理解远程推送,首先咱们须要了解其原理.html

iOS app大多都是基于C/S模式开发的,也就是 客户端/服务器模式,客户端也就是咱们用来安装app的手机,服务器是为客户端提供数据用的.由于也被称为Provider . 这种模式存在一个问题,那就是当app处理Terminate状态时,二者之间是没法进行通信的.为了解决这个问题 苹果所提供的一套服务称之为Apple Push Notification service,就是咱们所谓的APNs。服务器

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

    咱们的设备联网时(不管是蜂窝联网仍是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

  • 是什么: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是会变化的。

二.App应用远程推送

    1.注册推送通知

// 这里咱们用的是极光推送 编码

- (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];
    }
}

    2.注册成功以后将 deviceToken传到服务器

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    // Required
    [APService registerDeviceToken:deviceToken];
}

    3.处理收到的远程推送消息

-(void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo 

在上面的两个方法中处理收到的远程推送消息spa

    当App收到远程推送消息时,app不会有任何回调 ,只有用户手动点击通知栏里的通知(或者是收到通知时的弹窗)才会触发以上两个回调方法 .code

  • 当app从Terminate(关闭状态) -->前台 , 此时会走第一个方法 此时 launchoptions 不为空 (平时点击app进入前台时也会调用这个方法不过此时的launchoptions为空) .  能够经过判断 launchoptions 是否为空判断是否收到了远程通知 ,而后再对通知的内容进行处理 ,好比说根据推送内容的不一样跳转到不一样的页面 等等...
  • 当app从后台-->前台, 此时调用第二个方法 ,在这个方法中根据推送通知的内容进行相应的处理 

    须要注意的是:若是当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

相关文章
相关标签/搜索