iOS開發(fā)之新版APNs搭建必備知識

本文的大部分內(nèi)容是對蘋果關(guān)于APNs官方文檔的翻譯以及整理。

一、設(shè)備token和消息的生命周期

關(guān)于設(shè)備token以及推送消息的生命周期需要注意下面幾點(diǎn):

  • Token會在iOS系統(tǒng)更新或者設(shè)備數(shù)據(jù)、設(shè)置被擦除的時候改變。
  • 當(dāng)設(shè)備離線的時候,APNS會將消息數(shù)據(jù)存儲一段時間,等設(shè)備上線后重發(fā)。如果設(shè)備在離線期間,向APNS發(fā)送了多條推送消息,APNS將會丟棄掉前面的一些消息,只保留后面的消息,要是設(shè)備長時間離線,則會將所有的消息丟棄掉。
  • 可以通過設(shè)置http/2頭中的apns-collapse-id鍵值對來合并消息,比如:apns-collapse-id : 2,那么value為2的消息將被APNS合并成一條消息推送給設(shè)備。

二、Provider(后臺)與APNs的交互

Provider(即,APP的后臺)與APNS有兩種安全的交互方式,都必須采用TLS以保證可靠性,更詳細(xì)的內(nèi)容繼續(xù)往下看。

TLS的簡單理解是,為了保證數(shù)據(jù)傳輸安全,在HTTP層與TCP層之間插入的一個安全校驗(yàn)層,它所做的事情簡單來說就是:“通過CA申請的證書驗(yàn)證client與server是可靠的之后,通過相應(yīng)的公私鑰加密一個協(xié)商的公鑰,之后的真實(shí)數(shù)據(jù)傳輸就使用這個公鑰進(jìn)行加密,以保證數(shù)據(jù)的安全可靠性”,關(guān)于TLS的更詳細(xì)的介紹,可以參考這篇文章

基于Token的方式(Token-Based Provider-to-APNs Trust)

1、流程概述

這種方式適合在基于HTTP/2協(xié)議的Provider使用,它與APNs之間的連接通過JWT(JSON web tokens)來驗(yàn)證。在這種方式下不需要使用證書+私鑰的方式來建立可靠連接。Provider只需要提供一對公私鑰(私鑰Provider自己保存,公鑰蘋果保存),并使用其中的私鑰生成并加密JWT Token,每次向APNs請求推送的時候帶上這個Token即可。

具體步驟如下:

  1. Provider通過TLS向APNs發(fā)起請求。
  2. APNs返回一個證書給Provider。
  3. Provier驗(yàn)證這個證書。通過后,發(fā)送push數(shù)據(jù)并帶上JWT token。
  4. APNs驗(yàn)證token,并返回請求的結(jié)果。
Establishing and using token-based connection trust between a provider and APNs
Establishing and using token-based connection trust between a provider and APNs

建立TLS連接必須要有一個GeoTrust Global CA root certificate,在macOS中,這個證書已經(jīng)安裝在keychain中,如果是其他操作系統(tǒng)則可以在GeoTrust Root Certificates website下載。

2、Provider Authentication Tokens

關(guān)于JWT(JSON Web Token)的詳細(xì)資料可以通過這里了解。同時也可以從這里找到一些現(xiàn)成可用的庫。

下面對JWT進(jìn)行詳細(xì)的介紹,一個JWT實(shí)際上是一個JSON對象,它的頭部必須包含:

  • 用以加密token的加密算法(alg) ,比如:ES256。
  • 10個字符長度的標(biāo)識符(kid),(登入蘋果開發(fā)者賬號后,進(jìn)入到Certificates, Identifiers & Profiles,然后點(diǎn)擊APNs Auth Key,最后在右側(cè)找到Apple Push Notification Authentication Key (Sandbox & Production)選項(xiàng),點(diǎn)擊創(chuàng)建后可以創(chuàng)建一個p8文件。)

同時他的claims payload部分必須包含:

  • issuer(iss) registered claim key,其值就是10個字符長的Team ID。
  • issued at (iat) registered claim key,其值是一個秒級的UTC時間戳。

比如:

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

創(chuàng)建完這個token后,必須使用自己的私鑰對其進(jìn)行加密,然后再采用基于P-256曲線和SHA-256哈希算法的橢圓曲線數(shù)字簽名算法(ECDSA)進(jìn)行簽名,并將alg鍵的值設(shè)置為ES256。(注意:APNs只支持ES256簽名的JWT,否則會返回InvalidProviderToken(403)錯誤)

為了保證安全,APNs要求定期更新token,時間間隔為1小時,如果APNs發(fā)現(xiàn)當(dāng)前的時間戳與iat值中的時間戳相比,大于一個小時,那么APNs會拒絕推送消息,并返回ExpiredProviderToken (403)錯誤。

基于證書的方式(Certificate-based connection trust)

流程概述

這種方式是指Provider可以采用一個唯一的證書以及一個加密的私鑰來與APNs交互,其中證書是由蘋果產(chǎn)生的(通過蘋果賬號登錄到developer account配置創(chuàng)建)。整個交互過程如下:

  1. Provider通過TLS向APNs請求連接。
  2. APNs向Provider返回一個APNs證書。
  3. Provider驗(yàn)證這個APNs證書,并將從蘋果官網(wǎng)獲取的證書返回給APNs。
  4. APNs驗(yàn)證通過后,這個鏈接就算是建立了。
Establishing certificate-based connection trust between a provider and APNs
Establishing certificate-based connection trust between a provider and APNs

APNs Provider Certificates

創(chuàng)建步驟可以參考Configure push notifications中的Generate a universal APNs client SSL certificate章節(jié)。

三、APNs連接

連接的管理

蘋果的兩個APNs server分別為:

  • Development server: api.development.push.apple.com:443
  • Production server: api.push.apple.com:443

要與APNs交互要求server必須支持1.2及上版本的TLS協(xié)議。通過上面的介紹我們已經(jīng)知道,server跟APNs交互有兩種方式:基于JWT的方式以及基于證書的方式。為了保證高質(zhì)量的使用APNs應(yīng)該注意如下幾點(diǎn):

  • 對于基于JWT的方式,應(yīng)該定時更新token,token的有效期為1小時。
  • 對于基于JWT的方式,能每次請求都創(chuàng)建新的token,盡量在一小時內(nèi)使用同一個token。
  • 不能頻繁的建立、關(guān)閉連接,否則APNs會把這當(dāng)做是黑客攻擊,拒絕訪問。應(yīng)該盡量將連接?;?,直到你認(rèn)為這個連接接下來會長時間不使用為止。
  • 當(dāng)需要發(fā)送大量的推送數(shù)據(jù)的時候,可以同時創(chuàng)建多個連接,以改善性能。
  • 當(dāng)?shù)蹁N證書或者token時,應(yīng)該關(guān)閉所有相關(guān)的連接。

HTTP/2的請求與響應(yīng)

詳情可參見蘋果官方文檔HTTP/2 Request to APNs。這里介紹了接口的請求參數(shù)、返回結(jié)果,錯誤碼以及示例代碼。下面僅截取了其中的例子,以加深對APNs的使用的理解:

  • 基于證書的方式的request:

    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 //可以不填,如果不填A(yù)PNs會自己創(chuàng)建一個UUID并在response中返回
      apns-expiration = 0
      apns-priority = 10
    DATA
      + END_STREAM
        { "aps" : { "alert" : "Hello" } }
    
  • 基于token方式的request:

    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" } }
    
    
  • 失敗后的response:

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

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

四、設(shè)備token的生成與分發(fā)

在app啟動的時候,必須向iOS系統(tǒng)注冊遠(yuǎn)程推送,成功后,蘋果將會返回一個設(shè)備token給app,此時app就可以將這個token上報給自己的后臺。

如果有必要產(chǎn)生一個新的token,APNs會使用設(shè)備證書生成一個token(其中包含了一個設(shè)備ID),并使用token key加密后返回給設(shè)備。同時設(shè)備會將這個token以NSData對象的形式返回給app,app獲取到該token之后應(yīng)該將其發(fā)送到自己后臺,后臺之后就可以通過這個token來發(fā)送推送數(shù)據(jù)。過程如下圖:

Managing the device token
Managing the device token

最后

通過蘋果的官方文檔我們可以知道provider與APNs的交互過程中,需要注意一下幾點(diǎn):

  • 推薦使用HTTP/2協(xié)議。
  • 必須加入TLS層。
  • 基于JWT的方式,token的最大有效期為1小時,并且不能頻繁更換token。
  • 不能頻繁創(chuàng)建、關(guān)閉連接,應(yīng)該盡量少開連接,如果過于頻繁,APNs將把其當(dāng)做是黑客攻擊,但是如果數(shù)據(jù)量大,可以同時多個連接向APNs發(fā)送消息。
  • 吊銷token或者證書的時候,應(yīng)該及時關(guān)閉老的連接。

參考文獻(xiàn)

  1. APNs Overview
  2. Communicating with APNs
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容