系统推送的集成(十) —— 本地和远程通知编程指南之苹果推送通知服务APNs - 与APNs通信(三)

版本记录

版本号 时间
V1.0 2018.07.14

前言

我们做APP很多时候都需要推送功能,以直播为例,如果你关注的主播开播了,那么就需要向关注这个主播的人发送开播通知,提醒用户去看播,这个只是一个小的方面,具体应用根据公司的业务逻辑而定。前面已经花了很多篇幅介绍了极光推送,其实极光推送无非就是将我们客户端和服务端做的很多东西封装了一下,节省了我们很多处理逻辑和流程,这一篇开始,我们就利用系统的原生推送类结合工程实践说一下系统推送的集成,希望我的讲解能让大家很清楚的理解它。感兴趣的可以看上面几篇。
1. 系统推送的集成(一) —— 基本集成流程(一)
2. 系统推送的集成(二) —— 推送遇到的几个坑之BadDeviceToken问题(一)
3. 系统推送的集成(三) —— 本地和远程通知编程指南之你的App的通知 - 本地和远程通知概览(一)
4. 系统推送的集成(四) —— 本地和远程通知编程指南之你的App的通知 - 管理您的应用程序的通知支持(二)
5. 系统推送的集成(五) —— 本地和远程通知编程指南之你的App的通知 - 调度和处理本地通知(三)
6. 系统推送的集成(六) —— 本地和远程通知编程指南之你的App的通知 - 配置远程通知支持(四)
7. 系统推送的集成(七) —— 本地和远程通知编程指南之你的App的通知 - 修改和显示通知(五)
8. 系统推送的集成(八) —— 本地和远程通知编程指南之苹果推送通知服务APNs - APNs概览(一)
9. 系统推送的集成(九) —— 本地和远程通知编程指南之苹果推送通知服务APNs - 创建远程通知Payload(二)

Communicating with APNs - 与APNs通信

APNs providerAPI允许您向APNs发送远程通知请求。 然后,APNs会在iOS,tvOS和macOS设备上向您的应用程序发送通知,并通过iOS向Apple Watch发送通知。

providerAPI基于HTTP / 2网络协议。 每个交互都从您的provider的POST请求开始,该请求包含JSON的payloaddevice token。 APNs将通知payload转发到由请求包含的设备令牌标识的特定用户设备上的应用程序。

provider是您配置为使用APNs的部署和管理的服务器。


Provider Authentication Tokens - provider认证令牌

要安全地连接到APNs,您可以使用provider身份验证token或provider证书。本节介绍使用token的连接。

provider API支持JSON Web Token(JWT)规范,允许您将语句和元数据(称为claims)传递给APNs,以及每个推送通知。有关详细信息,请参阅https://tools.ietf.org/html/rfc7519上的规范。有关JWT的其他信息,以及用于生成签名JWT的可用库列表,请参阅https://jwt.io

provider身份验证token是您构造的JSON对象,其标头必须包含:

  • 用于加密令牌的加密算法(alg)
  • your developer account获取的10个字符的key标识符(kid)密钥

token的声明payload必须包括:

  • 发布人(iss)注册的claim密钥,其值为您的10个字符的团队ID,从your developer account获得。
  • 已发布(iat)注册的claim密钥,其值表示生成token的时间,以自Epoch以来的秒数(UTC)表示。

创建token后,您必须使用私钥对其进行签名。然后,您必须使用带有P-256曲线和SHA-256哈希算法的Elliptic Curve Digital Signature Algorithm (ECDSA)加密token。在算法header(alg)中指定值ES256。有关如何配置token的信息,请参阅Xcode帮助中的Configure push notifications

APNs的解码JWT provider身份验证token具有以下格式:

{
    "alg": "ES256",
    "kid": "ABC123DEFG"
}
{
    "iss": "DEF123GHIJ",
    "iat": 1437179036
 }

注意:APNs仅支持使用ES256算法签名的provider身份验证token。 不安全的JWT或使用其他算法签名的JWT将被拒绝,您的提供程序将收到InvalidProviderToken(403)响应。

为了确保安全性,APNs需要定期生成token。 新token具有在claim密钥处发布的更新,其值指示token生成的时间。 如果token问题的时间戳不在最后一小时内,则APNs拒绝后续推送消息,返回ExpiredProviderToken(403)错误。

如果您怀疑provider token签名密钥已泄露,您可以从 your developer account撤消该密钥。 您可以发出新的密钥对,然后可以使用新的私钥生成新的密钥。 为了最大限度地提高安全性,请关闭所有使用已使用且已撤销密钥签名的令牌的APNs的连接,并在使用使用新密钥签名的令牌之前重新连接。


APNs Provider Certificates - APNs Provider证书

您按照Xcode帮助中的Configure push notifications中的说明获得的APNs provider证书可以连接到APNs的生产和开发Production and Development环境。

您可以使用您的APNs证书向您的主应用程序发送通知,如其bundle ID,以及与该应用程序关联的任何Apple Watch复杂功能或后备VoIP服务。 使用证书中的(1.2.840.113635.100.6.3.6)扩展名来标识推送通知的主题。 例如,如果您为应用程序提供了包ID com.yourcompany.yourexampleapp,则可以在证书中指定以下主题:

    1. Extension ( 1.2.840.113635.100.6.3.6 )
    1. Critical NO
    1. Data com.yourcompany.yourexampleapp
    1. Data app
    1. Data com.yourcompany.yourexampleapp.voip
    1. Data voip
    1. Data com.yourcompany.yourexampleapp.complication
    1. Data complication

APNs Connections - APNs连接

发送远程通知的第一步是与相应的APNs服务器建立连接:

  • 开发服务器:api.development.push.apple.com:443
  • 生产服务器:api.push.apple.com:443

注意:您也可以在与APNs通信时使用端口2197。 例如,您可以执行此操作,以允许APNs通过防火墙,但阻止其他HTTPS流量。

连接到APNs时,您的provider必须支持TLS 1.2或更高版本。您可以使用从开发人员帐户获得的provider客户端证书,如Creating a Universal Push Notification Client SSL Certificate中所述。

要在没有APNs provider证书的情况下进行连接,您必须创建一个provider身份验证token,使用通过your developer account配置的密钥进行签名(请参阅Xcode帮助中的Configure push notifications)。拥有此token后,您可以开始发送推送消息。然后,您必须定期更新token;每个APNs provider身份验证token的有效间隔为一小时。

APNs允许每个连接有多个并发流。确切的流数量因您使用provider证书或身份验证token而异,并且根据服务器负载的不同而不同。不要假设特定数量的流。

使用token而不是证书建立与APNs的连接时,在连接上只允许一个流,直到您发送带有有效 provider身份验证token的推送消息。 APNs忽略HTTP / 2 PRIORITY帧,因此不要在您的流上发送它们。

1. Best Practices for Managing Connections - 管理连接的最佳实践

通过多个通知保持与APNs的连接;不要反复打开和关闭连接。 APNs将快速连接和断开视为拒绝服务攻击。您应该保持连接处于打开状态,除非您知道它将在一段时间内处于空闲状态 - 例如,如果您每天只向用户发送一次通知,则可以接受每天使用新连接。

不要为您发送的每个推送请求生成新的 provider身份验证token。获取token后,在token的有效期(即整整一小时)内继续将其用于所有推送请求。

您可以与APNs服务器建立多个连接以提高性能。发送大量远程通知时,请将它们分配到多个服务器端点的连接。与使用单个连接相比,通过让您更快地发送远程通知并让APNs更快地提供它们,这可以提高性能。

如果撤消了 provider证书,或者revoke了用于签署 provider token的密钥,请关闭所有与APNs的现有连接,然后打开新连接。

您可以使用HTTP / 2 PING框架检查连接的运行状况。

2. Terminating an APNs Connection - 终止APNs连接

如果APNs决定终止已建立的HTTP / 2连接,它将发送GOAWAY帧。 GOAWAY帧在其有效载荷中包含带有reason密钥的JSON数据,其值表示连接终止的原因。 有关reason键的可能值列表,请参阅Table 8-6

正常请求失败不会导致连接终止。


APNs Notification API - APNs 通知 API

APNs Provider API包含您使用HTTP / 2 POST命令配置和发送的请求和响应。 您使用该请求向APNs服务器发送推送通知,并使用该响应来确定该请求的结果。

1. HTTP/2 Request to APNs - HTTP/2 请求 APNs

使用请求向特定用户设备发送通知。

Table 8-1 HTTP/2 request fields

Name Value
:method POST
:path /3/device/<device-token>

对于<device-token>参数,请指定目标设备的device token的十六进制字节。

APNs需要使用HP​​ACKHTTP / 2的标头压缩),这可以防止重复的标头密钥和值。 APNs为HPACK维护一个小型动态表。为了避免填写APNs HPACK表并且必须丢弃表数据,请按以下方式对header进行编码 - 尤其是在发送大量流时:

  • :path值应编码为文字头字段而不进行索引
  • authorization请求标头(如果存在)应编码为文字标题字段而不进行索引
  • 用于apns-idapns-expirationapns-collapse-id请求标头的适当编码根据它是初始操作还是后续POST操作的一部分而有所不同,如下所示:
    • 第一次发送这些标头时,使用incremental indexing对它们进行编码,以允许将标头名称添加到动态表中。
    • 随后您将发送这些header,将它们编码为literal header fields而不进行indexing编码。

使用incremental indexing将所有其他标头编码为文字标题字段。有关标头编码的详细信息,请参阅tools.ietf.org/html/rfc7541#section-6.2.1和tools.ietf.org/html/rfc7541#section-6.2.2。

APNs忽略除表8-2中列出的请求标头之外的请求标头。

Table 8-2 APNs request headers

消息的正文内容是通知的有效负载的JSON字典对象。 不得压缩正文数据,其最大大小为4KB(4096字节)。 对于因特网协议语音(VoIP)通知,主体数据最大大小为5KB(5120字节)。 有关要包含在正文内容中的键和值的信息,请参阅Payload Key Reference

2. HTTP/2 Response from APNs - HTTP/2 响应APNs

对请求的响应具有表8-3中列出的格式。

Table 8-3APNs response headers

表8-4列出了请求的可能状态代码。 这些值包含在响应的:status标头中。

Table 8-4Status codes for an APNs response

对于成功请求,响应正文为空。 失败时,响应正文包含一个JSON字典,其中包含表8-5中列出的键。 当连接终止时,此JSON数据也可能包含在GOAWAY帧中。

Table 8-5 APNs JSON data keys

表8-6 列出了响应的JSON有效负载的reason键中包含的可能错误代码。

Table 8-6 Values for the APNs JSON reason key

3. HTTP/2 Request/Response Examples for APNs - HTTP/2 APNs 请求响应示例

Listing 8-1显示了为provider证书构造的示例请求

// Listing 8-1Sample request for a certificate with a single topic

HEADERS
  - END_STREAM
  + END_HEADERS
  :method = POST
  :scheme = https
  :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
  host = api.development.push.apple.com
  apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b
  apns-expiration = 0
  apns-priority = 10
DATA
  + END_STREAM
    { "aps" : { "alert" : "Hello" } }

LIsting 8-2显示了为provider身份验证token构造的示例请求

// Listing 8-2 Sample request for a provider authentication token

HEADERS
  - END_STREAM
  + END_HEADERS
  :method = POST
  :scheme = https
  :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
  host = api.development.push.apple.com
  apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b
  apns-expiration = 0
  apns-priority = 10
  apns-topic = <MyAppTopic> 
DATA
  + END_STREAM
    { "aps" : { "alert" : "Hello" } }
HEADERS
  - END_STREAM
  + END_HEADERS
  :method = POST
  :scheme = https
  :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
  host = api.development.push.apple.com
  authorization = bearer eyAia2lkIjogIjhZTDNHM1JSWDciIH0.eyAiaXNzIjogIkM4Nk5WOUpYM0QiLCAiaWF0I
 jogIjE0NTkxNDM1ODA2NTAiIH0.MEYCIQDzqyahmH1rz1s-LFNkylXEa2lZ_aOCX4daxxTZkVEGzwIhALvkClnx5m5eAT6
 Lxw7LZtEQcH6JENhJTMArwLf3sXwi
  apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b
  apns-expiration = 0
  apns-priority = 10
  apns-topic = <MyAppTopic>
DATA
  + END_STREAM
    { "aps" : { "alert" : "Hello" } }

Listing 8-3显示了为包含多个主题的证书构建的示例请求。

// Listing 8-3 Sample request for a certificate with multiple topics

HEADERS
  - END_STREAM
  + END_HEADERS
  :method = POST
  :scheme = https
  :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
  host = api.development.push.apple.com
  apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b
  apns-expiration = 0
  apns-priority = 10
  apns-topic = <MyAppTopic> 
DATA
  + END_STREAM
    { "aps" : { "alert" : "Hello" } }

Listing 8-4显示了成功推送请求的示例响应。

// Listing 8-4Sample response for a successful request

HEADERS
  + END_STREAM
  + END_HEADERS
  apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b
  :status = 200

Listing 8-5显示了发生错误时的示例响应。

// Listing 8-5Sample response for a request that encountered an error

HEADERS
  - END_STREAM
  + END_HEADERS
  :status = 400
  content-type = application/json
    apns-id: <a_UUID>
DATA
  + END_STREAM
  { "reason" : "BadDeviceToken" }

后记

本篇主要讲述了与APNs通信,感兴趣的给个赞或者关注~~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容