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

2017-02-13 13:56:23 +08:00
 jpush

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

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

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

准备篇


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

原理篇


Tip 2 :推送通知本身是 iOS 系统的行为,所以在 App 没有运行(没有在前台也没有在后台)的时候:

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

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

    #ifdef __IPHONE_8_0
    if ([[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 ```

  1. 在第一次触发这段代码的时候,会有一个系统弹窗,询问你是否允许该 App 要给你推送信息。当你选择允许时,系统会打包 App+手机唯一标识+证书 信息发送至 APNs 服务器注册推送服务, APNs 系统会对该手机安装的该 App 是否有推送权限进行验证,所以必须要加入了 Apple Deveice 的手机,使用对应 App 的推送证书才能够成功的注册。

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

    -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {  
    	[JPUSHService registerDeviceToken:deviceToken];//将 deviceToken 传给极光推送
    }
    
  3. 如果以上步骤均成功,此时你能够取到第三方提供的设备注册 id 。能否取到该 id 值,可以作为判断设备是否能够成功推送的标准(见 Tip 6 - Registration ID )。因为当你取到该值时必然:

  1. 综上,注册及接收推送必须使用真机,必须连网。

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

  1. 使用你们公司或第三方的服务端向 APNs 发送推送请求(请参考苹果 APNs 相关资料,或者第三方推送提供了更简单的 REST API )。
  2. APNs 接收并验证推送请求。
  3. APNs 找到设备下发推送。
  4. 手机收到推送通知,系统根据 App 状态进行处理:
    • 前台收到:
      • 系统会将通知内容传到 didReceiveRemoteNotification
    • 后台收到:
      • 如果开启了 Remote Notification ,系统将推送传到 didReceiveRemoteNotification:fetchCompletionHandler:(见 Tip 5 - 后台推送),否则此时代码中收不到推送。
      • 展示横幅、通知中心、声音、角标。
    • 退出收到:
      • 如果点击推送横幅 /通知中心而启动 App ,系统将通知传到 didFinishLaunchingWithOptions
      • 展示横幅、通知中心、声音、角标。

推送通知内容篇


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

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

- 后台推送
  - 各种显示效果跟普通推送完全一样。
  - 必须携带 `"content-available" = 1;`
  - 必须携带 `alert`、`badge`、`sound` 中 `至少 1 个字段`。
  - 仅 iOS 7 以后支持。
  - 必须在 Xcode 工程中 TARGETS - Capabilities - Background Modes - Remote notifications 开启该功能,具体可参照 [iOS 7 Background Remote Notification]( http://docs.jiguang.cn/client/ios_tutorials/#ios-7-background-remote-notification)。
  - App :
    - 处于前台,可通过`didReceiveRemoteNotification`( iOS 7 before )`didReceiveRemoteNotification:fetchCompletionHandler:`( iOS 7 after ) 获取通知内容。
    - 处于后台,可通过 `didReceiveRemoteNotification:fetchCompletion
    Handler:` 获取通知内容  // 获取情况中与普通推送的唯一不同点,此时 iOS 系统允许开发者在 App 处于后台的情况下,执行一些代码,大概提供几分钟的时间,可以用来偷偷的刷新 UI 、切换页面、下载更新包等等操作。
    - 处于退出,无法获取通知内容。
    - 点击图标启动,无法获取通知内容。
    - 点击推送横幅启动,在 `didFinishLaunchingWithOptions` 获取通知内容。
  - 通知内容类似如下:

    ```json
{
      "_j_msgid" = 2090737306;
      aps =     {
        alert = "显示内容";
        badge = 1;
        "content-available" = 1;  // 必带字段
        sound = default;
      };
      key1 = value1;
}
    ```
  ​
- 静默推送
  - 没有任何展示效果。
  - 必须携带 `"content-available" = 1;`,因此静默必然是后台的。
  - 必须不携带 `alert`、`badge`、`sound`。
  - 可携带自定义字段。
  - App :
    - 处于前台,可通过`didReceiveRemoteNotification`( iOS 7 before )`didReceiveRemoteNotification:fetchCompletionHandler:`( iOS 7 after ) 获取通知内容。
    - 处于后台,可通过 `didReceiveRemoteNotification:fetchCompletion
    Handler:` 获取通知内容  //获取情况中与普通推送的唯一不同点,此时 iOS 系统允许开发者在 App 处于后台的情况下,执行一些代码,大概提供几分钟的时间,可以用来偷偷的刷新 UI 、切换页面、下载更新包等等操作。
    - 处于退出,无法获取通知内容。
  - 通知内容类似如下:

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

推送目标篇


别名、标签、 Registration ID 均是第三方提供的用于更方便地指定推送目标的功能。

Tip 6 :推送根据目标的不同可分为:

应用内消息篇


Tip 7 :应用内消息(以下简称消息 )和推送通知的区别,消息:

组合大招篇


Tip 8 : tags 的组合技巧

Tip 9 :通知+消息的组合技巧

| | 通知 | 消息 | | :--: | :----------------------: | :------------: | | 送达时间 | 可能存在几秒延迟 | 几乎无延迟 | | 获取时机 | 处于前台或后台能获取内容 | 仅处于前台能获取内容 | | 离线内容 | 保留『一段时间』,过期会抛弃,无法查询历史内容 | 始终保留,可查询全部历史内容 | | 系统展示 | 会展示(静默推送或 App 处于前台不展示) | 不展示 |

2254 次点击
所在节点    问与答
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/340111

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX