版本记录
版本号 | 时间 |
---|---|
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 provider
API允许您向APNs发送远程通知请求。 然后,APNs会在iOS,tvOS和macOS设备上向您的应用程序发送通知,并通过iOS向Apple Watch发送通知。
provider
API基于HTTP / 2
网络协议。 每个交互都从您的provider
的POST请求开始,该请求包含JSON的payload
和device 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
,则可以在证书中指定以下主题:
Extension ( 1.2.840.113635.100.6.3.6 )
Critical NO
Data com.yourcompany.yourexampleapp
Data app
Data com.yourcompany.yourexampleapp.voip
Data voip
Data com.yourcompany.yourexampleapp.complication
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需要使用HPACK
(HTTP / 2
的标头压缩),这可以防止重复的标头密钥和值。 APNs为HPACK
维护一个小型动态表。为了避免填写APNs HPACK
表并且必须丢弃表数据,请按以下方式对header进行编码 - 尤其是在发送大量流时:
-
:path
值应编码为文字头字段而不进行索引 -
authorization
请求标头(如果存在)应编码为文字标题字段而不进行索引 - 用于
apns-id
,apns-expiration
和apns-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通信,感兴趣的给个赞或者关注~~~~