本文旨在对 iOS 推送(以下简称 推送)进行一个完整的剖析,如果你之前对推送一无所知,那么在你认真地阅读了全文后必将变成一个推送老手,你将会对其中的各种细节和原理有充分的理解。以下是 pikacode 使用 iOS 推送的一些经验,欢迎互相交流,指出错漏之处。

推送服务 可以说是所有 App 的标配,不论是哪种类型的 App,推送都从很大程度上决定了 App 的 打开率、使用率、存活率 。因此,熟知并掌握推送原理及方法,对每一个开发者来说都是必备技能,对每一个依赖 App 的公司来说都至关重要。

从 iOS 10 新增的 UserNotifications Framework 可以发现,Apple 整合了原有散乱的 API,并且增加了许多强大的功能。以 Apple 官方的角度来看,也必然是相当重视推送服务对 App 的影响、以及对 Apple 生态圈长远发展的影响。

准备篇


Tip 1:推送 必须 购买 Apple 开发者账号,并使用特定的 推送证书

  • 使用免费帐号不能推送

  • 那如果我们使用的是第三方推送服务(以下简称 第三方 )呢?比如「极光推送」。也必须购买开发者帐号。因为所有的第三方都会将推送请求发至 APNs(Apple Push Notification service 苹果推送通知服务),所有推送均是由 APNs 下发。

  • 如何注册及正确的配置证书,参考这里 iOS 证书设置指南

原理篇


Tip 2:推送本身是 iOS 系统的行为,所以在 App 没有运行的时候:

  • 仍然能够推送及接收(通知中心通知、顶部弹窗、刷新 App 右上角的小圆点即 badge [以下简称 角标] 等都会由系统来控制和展示)

  • 收到推送时,是无法在 App 的代码中获取到推送内容的。因为沙盒机制,此时 App 的任何代码都不可能被执行

Tip 3:手机向 APNs 注册推送服务

  1. 在代码中注册推送服务:

    #ifdef __IPHONE_8_0if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {     UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil];
         [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    } else {     UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
         [[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
    }#else
         UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
         [[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];#endif
  2. 在第1次触发这段代码的时候,会有1个系统弹窗,询问你是否允许该 App 要给你推送信息。当你选择 允许 时,系统会打包 App+手机唯一标识+证书 信息发送至 APNs 服务器注册推送服务,APNs 系统会对该手机安装的该 App 是否有推送权限进行验证,所以必须要加入了 Apple Deveice 的手机,使用对应 App 的 推送证书 才能够成功的注册。

  3. 如果注册成功,则可以在 AppDelegate.m 的如下方法中获取到 deviceToken,它是对 该手机+该App 组合的一个唯一标识,当使用远程推送时,只需将推送消息发给指定的 deviceToken 即可使推送信息传达给指定手机的指定 App 上。因此如果你使用第三方,就需要在这个方法里将 deviceToken 传给第三方。(在 iOS 9 为了更好的保护用户隐私,会出现多次重复删除/安装 App 导致 deviceToken 不断变化的情况)

    -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {  
       [JPUSHService registerDeviceToken:deviceToken];//将 deviceToken 传给极光推送}
  4. 综上,注册及接收推送 必须 使用真机,必须 连网

Tip 4:推送从 服务端 --> App 代码 的过程

  1. 使用你们公司或第三方的服务端向 APNs 发送推送请求(包含 推送内容+App描述+手机描述 )

  2. APNs 接收并验证推送请求

  3. APNs 利用网络搜索并定位指定设备,下发推送

  4. 手机收到推送,系统根据 App 状态进行处理

    • 前台收到:

      • 系统会将推送内容传到 didReceiveRemoteNotification

    • 后台收到:

      • 如果开启了 Remote Notification ,系统将推送传到 didReceiveRemoteNotification:fetchCompletionHandler:(见 Tip 5 - 后台推送)

      • 展示弹窗、推送中心、声音、角标

    • 退出收到:

      • 如果点击推送弹窗/通知中心而启动 App,系统将推送传到 didFinishLaunchingWithOptions

      • 展示弹窗、推送中心、声音、角标

推送内容篇


Tip 5:推送分为 本地/远程 2 种类型:

  • 本地推送,可指定推送时间,在该时间准时弹出推送通知

  • 远程推送,分为 普通推送/后台推送/静默推送 3 种类型。存在延迟问题(由于 Tip 1 第 2 点,APNs 的不稳定及高峰时段的巨量请求所致)

    • 普通推送

      • 就是我们在手机上平时见到的推送

      • 包含声音、弹窗、角标、自定义字段

      • App

        • 处于前台,不会弹窗,可通过 didReceiveRemoteNotification 获取推送内容(前台弹窗的方法看这里

        • 处于后台,会弹窗,无法获取推送内容

        • 处于退出,会弹窗,无法获取推送内容

        • 点击图标启动,无法获取推送内容

        • 点击推送弹窗启动,在 didFinishLaunchingWithOptions 获取推送内容

      • 推送内容类似如下:

        {
          "_j_msgid" = 200806057;//第三方附带的 id,用于在后台查询送达情况
          aps =     {
            alert = "显示内容";
            badge = 1;//App 角标,可推送 n、+n、-n 来实现角标的固定、增加、减少
            sound = default;//推送声音,默认系统三全音,如需使用自己的声音,需要将声音文件拖拽&拷贝至 Xcode 工程目录任意位置,并在推送时指定其文件名
          };
          key1 = value1;//自定义字段,可设置多组,用于处理内部逻辑
          key2 = value2;
        }
    • 后台推送

      • 各种显示效果跟普通推送完全一样

      • 必须携带 "content-available" = 1;

      • 必须携带 alertbadgesound 中 至少 1 个字段

      • 仅 iOS 7 以后支持

      • 必须在 Xcode 工程中 TARGETS - Capabilities - Background Modes - Remote notifications 开启该功能,具体可参照 iOS 7 Background Remote Notification

      • App

        • 处于前台,可通过 didReceiveRemoteNotification 获取推送内容

        • 处于后台,可通过didReceiveRemoteNotification:fetchCompletionHandler: 获取推送内容//获取情况中与 普通推送 的唯一不同点,此时 iOS 系统允许开发者在 App 处于后台的情况下,执行一些代码,大概提供几分钟的时间,可以用来偷偷的刷新 UI、切换页面、下载更新包等等操作

        • 处于退出,无法获取推送内容

        • 点击图标启动,无法获取推送内容

        • 点击推送弹窗启动,在 didFinishLaunchingWithOptions 获取推送内容

    • 推送内容类似如下:

      {
          "_j_msgid" = 2090737306;
            aps =     {
            alert = "显示内容";
            badge = 1;
            "content-available" = 1;//必带字段
            sound = default;
          };
          key1 = value1;
      }
    • 静默推送

      • 必须携带 "content-available" = 1;,因此静默必然是后台的

      • 必须不携带 alertbadgesound

      • 可携带自定义字段

      • 在用户完全不知情的情况下被 App didReceiveRemoteNotification 接收并处理(仅限 App 处于前台时,其他状态因没有任何提示,故无法被用户触发并被代码截获。)

      • 推送内容类似如下:

        {
          "_j_msgid" = 3938587719;
          aps =     {
            alert = "";
            "content-available" = 1;//必带字段
          };
          key1 = value1;
        }

别名/标签篇


别名、标签、Registration ID 均是第三方提供的用于分类推送的功能。

Tip 6:推送根据对象的不同可分为:

  • 广播

    • 无差别发送给所有用户

  • 别名 alias 推送

    • 1 个手机的 1 款 App 只能设置 1 个 alias(可修改)

    • 用于指定一些基本属性,如男/女性用户

    • 推送时可指定多个 alias 来下发同一内容

    • 仅指定 alias 的用户能够收到推送

  • 标签 tag 推送

    • 可设置多个、可增加、清空

    • 用于指定多样的属性,如 1000+daily+discount 可用于表示 月消费超过 1k喜欢购买日用品偏好折扣商品 的用户

    • 如果要 删除,需要在上次设置时,将设置的 tags 保存至 NSUserDefaults,本次剔除不需要的 tag 后,再重新设置

    • 推送时可指定多个 tag 来下发同一内容

    • 手机如果设置了推送指定的多个 tag 中 任一个 tag,都能够收到推送消息。如指定 1000+globe+original (千元级消费者、全球购、原价),那么设置了 100+globe+discount(百元级消费者、全球购、折扣价)的用户可以收到该推送消息。

  • Registration ID 推送

    • 在 Tip 3 的第 3 步时将 deviceToken 提供给第三方之后,其服务器会自动生成的指向该手机的唯一 id

    • 可在推送时指定多个 id 来下发消息

    • 可用于对 核心用户旗舰用户 的 精准推送

自定义消息篇


Tip 7:自定义消息(以下简称 消息 )和推送的区别,消息:

  • 不需要 Apple 推送证书

  • 由第三方的服务器下发,而不是 APNs

  • 相比推送,更快速,几乎没有延迟,可用于 IM 消息的即时送达

  • 通过长连接技术下发消息,因此

    • 手机必须启动并与第三方服务器建立连接

    • 如果手机启动立刻切至后台,很可能连接没有建立

    • 手机必须处于前台才能收到消息

    • 手机从后台切回前台,会自动重新建立连接,并收到离线消息

  • 没有任何展示(弹窗、通知中心、角标、声音),因此可以:

    • 自定义字段实现 UI 效果

    • 完全在静默情况下处理 App 内部逻辑

    • 使用一些 App Store 审核不会通过的功能,在审核时关闭功能,上架后通过接收消息,开启相关功能

组合大招篇


Tip 8:tags 的组合技巧

  • 见 Tip 5 - 标签 tag 推送

  • 可以通过 App 自己的服务端来统计分析用户行为,然后将指定的 tags 发送至手机,手机接收后再为用户打上对应的 tags

Tip 9:推送+消息的组合技巧

  • 首先来看推送和消息各自的特性

    • 推送

      • 展示性:提醒作用

      • 延迟性:不稳定

      • 全局性:不论 App 处于哪种状态均能接收

      • 丢失性:因为各种网络原因,可能丢失。在客户端不能获取历史纪录。

    • 消息

      • 静默性:处理逻辑

      • 即时性:稳定

      • 前台性:只有处于前台才能收到

      • 存留性:必然送达。在客户端可以获取历史纪录。

  • 由于各自的特性都完全相反,因此 2 者结合使用是使得 App 性能最大化的必然选择:

    • 情景一:
      QQ/微信 聊天。会同时下发一组 推送+消息 ,如果用户没有启动 QQ,虽有延迟但必然能够先收到 推送,在受到推送的提醒之后,用户打开 App,此时收到了离线 消息,即时更新 UI,与好友即时的发送/接收消息。(在收到推送后,断网,然后启动 App,你会发现此时手机里并不会显示刚刚推送的内容,因为它是依靠拉取消息来刷新页面的,而不是不够稳定的推送)

    • 情景二:(期待您的补充...)

文章转自 Pikacode的简书
 

iOS 推送全解析的更多相关文章

  1. iOS 推送全解析,你不可不知的所有 Tips!

    本文旨在对 iOS 推送进行一个完整的剖析,如果你之前对推送一无所知,那么在你认真地阅读了全文后必将变成一个推送老手,你将会对其中的各种细节和原理有充分的理解.以下是 pikacode 使用 iOS ...

  2. iOS 10 推送全解析,注意事项

    本文旨在对 iOS 推送进行一个完整的剖析,如果你之前对推送一无所知,那么在你认真地阅读了全文后必将变成一个推送老手,你将会对其中的各种细节和原理有充分的理解.以下是 pikacode 使用 iOS ...

  3. iOS 推送问题全解答《十万个为啥吖?》

    Q 1:为啥收不到推送(1)? 如果收到推送时,App 在前台运行,那么: iOS 10 before 顶部横幅不会弹出.没有任何展示,你以为「没有收到推送」. iOS 10 after 如果没有实现 ...

  4. “iOS 推送通知”详解:从创建到设置到运行

    这是一篇编译的文章,内容均出自Parse.com的iOS开发教程,同时作者还提供了视频讲解.本文将带领开发者一步一步向着iOS推送通知的深处探寻,掌握如何配置iOS推送通知的奥义. 介绍一点点背景资料 ...

  5. iOS推送 再备

    这是一篇编译的文章,内容均出自Parse.com的iOS开发教程,同时作者还提供了视频讲解.本文将带领开发者一步一步向着iOS推送通知的深处探寻,掌握如何配置iOS推送通知的奥义. 介绍一点点背景资料 ...

  6. 手把手教你搞定个推iOS推送SDK集成

    以下是一位开发者在集成个推iOS推送SDK过程中的真实经历. 作者:Ezreallp 一次偶然的机会,公司的项目要用到推送,我自己本来就很懒,不愿意去弄整套APNS的流程,刚好之前跟朋友聊起过他们的产 ...

  7. iOS推送证书转pem文件

    iOS推送证书转 .pem文件. 推送证书转pem文件openssl x509 -in apns_miaobozhibo.cer -inform der -out apns_miaobozhibo.p ...

  8. IOS 推送-客户端处理推送消息

    IOS 推送-客户端处理推送消息 1.推送调用顺序 APN push的消息到达后,UIApplicationDelegate有两个方法和处理消息有关: 1)application:didReceive ...

  9. IOS 推送-配置与代码编写

    IOS 推送配置与代码编写 这里介绍IOS的推送,本文章已经在IOS6/7/8上都能运行OK,按照道理IOS9应该没问题. 大纲: 1.文章前提 2.推送介绍 3.推送文件账号设置 4.推送证书介绍 ...

随机推荐

  1. 正则表达式(/[^0-9]/g,'')中的"/g"是什么意思 ?

    正则表达式(/[^0-9]/g,'')中的"/g"是什么意思 ?     表达式加上参数g之后,表明可以进行全局匹配,注意这里“可以”的含义.我们详细叙述: 1)对于表达式对象的e ...

  2. VBA中操作XML

    OFFICE2007之后使用了OpenXml标准(伟大的改变),定制文本级的Ribbon可以通过修改压缩包内的xml文件来实现. 先学习一下VBA中操作XML的方法 先引用Microsoft XML ...

  3. JavaScript经典代码【一】【javascript HTML控件获取值】

    javascript HTML控件获取值 1.下拉列表框选定值 ddlPageSize.options[ddlPageSize.selectedIndex].value ddlPageSize.opt ...

  4. CUBRID学习笔记 6 修改用户密码

    修改密码 可以在web管理中修改. 还有另外两种体位 1  语句 ALTER USER user_name PASSWORD 'any_password_here_in_single_quotes'; ...

  5. 8.mybatis动态SQL模糊查询 (多参数查询,使用parameterType)

    多参数查询,使用parameterType.实例: 用户User[id, name, age] 1.mysql建表并插入数据 2.Java实体类 public class User { public ...

  6. git :设置 object-c 的忽略文件

    使用 git 命令行来进行版本控制的时候, 需要设置忽略文件. 这里能找到所有语言的忽略文件的内容:https://github.com/github/gitignore OBJECT的忽略文件内容: ...

  7. Codeforces Round #379 (Div. 2) C. Anton and Making Potions 二分

    C. Anton and Making Potions time limit per test 4 seconds memory limit per test 256 megabytes input ...

  8. oracle dba 职责, 及个人需要掌握内容

    ORACLE DBA 职责, 基本相当于日常工作. 0. 数据库设计 1. 模式对象的创建与管理(table, index 等等) 2. 事物管理, 例如并发等 3. SQL 调优 只是针对SQL的 ...

  9. jsonp实现原理详细介绍

    主要是浏览器的同源同域(协议相同,域名相同及端口相同)策略需要使用跨域获取数据,故需要jsonp跨域获取数据.重点:img的src,link的href及script的src不遵循浏览器的同源同域策略, ...

  10. python下载地址

    https://www.python.org/downloads/release/python-351/