目錄
一、簡介
二、APNs推送流程
三、什么是deviceToken
四、消息體
五、APNs推送中的問題
APNs 簡介
Apple Push Notification service (APNs),即蘋果推送通知服務。
為什么會有 APNs ?
由于移動設(shè)備內(nèi)存、CPU、電量的局限性,iOS 不允許 APP 的進程常駐后臺(事實上可以申請后臺運行一段時間,最長約10分鐘)。
當用戶主動殺掉APP或者APP進入后臺超過限定時長時,就意味著該APP進程的結(jié)束。這很大程度保障了前臺APP的流暢性,也延長了手機的使用時長。這也是蘋果用戶體驗好的原因之一。但是這也意味著,服務器無法主動和用戶交互(如推送實時消息等)。為了解決這個限制,蘋果推出了APNs,允許設(shè)備和服務器分別與蘋果的推送通知服務器保持長連接狀態(tài)。
iOS的通知
iOS分本地通知和遠程通知,(APNs)是遠程通知功能的核心.
- 本地通知是由本地應用觸發(fā)的。一般是基于時間的一種通知形式,如鬧鐘、待辦事件等的提醒。
- 遠程通知是通過我們自己的服務器推送消息的一種通知形式。
APNs推送流程
假如我們的蘋果設(shè)備(AC電腦、筆記本、iPad、iPhone等)安裝了一個名叫XXX的應用。那么我們具體是怎樣接收到推送通知的那??接下來我們就說說具體這個過程。下面是蘋果APNs官方簡介 中提供的APNs推送流程的圖

Provier 代表我們自己的應用服務器
APNs 代表蘋果的APNs推送服務器
接著是代表的就是蘋果的設(shè)備
Client App 代表我們開發(fā)的應用
說明:
- 安裝了XXX應用的蘋果設(shè)備需要向APNs服務器注冊,注冊成功后APNs服務器會返回一個deviceToken,并且二者之間會維持一個長連接(這個長連接是基于SSL協(xié)議的TCP流通訊)
- 拿到這個deviceToken后我們將這個deviceToken發(fā)給我們自己的服務器
- 當有消息需要被推送時,我們自己的服務器會將消息按指定的格式結(jié)合設(shè)備的deviceToken一并打包 然后發(fā)給APNs服務器
- APNs將新消息推送給我們的設(shè)備上,然后就在設(shè)備的屏幕上顯示出來了 (因為我們的設(shè)備和APNs服務器二者之間維持了一個長連接)
注意說明:
真正完成推送的是APNS服務器。消息一定是由APNs服務器推送給我們的設(shè)備的,我們自己的應用服務器只是將需要推送的消息告訴APNs服務器。至于如何維護消息隊列或如何保證消息能被推送到指定的設(shè)備上,這些都由蘋果APNs做好的。
什么是deviceToken ?
deviceToken是一個APP裝在一個設(shè)備上的唯一標識符。一個APP在不同的設(shè)備上deviceToken不一樣;一個APP刪除之后再次安裝deviceToken也不一樣。
在項目代碼AppDelegate里面有一個回調(diào)方法,當APNs注冊成功通過該回調(diào)方法可以獲取到返回的deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
上面說過當有消息需要被推送時,我們自己的服務器會將消息按指定的格式結(jié)合設(shè)備的deviceToken一并打包 ,APNs拿到這個包之后驗證這個包結(jié)構(gòu)是否正確并提取其中的信息后,再將消息推送到指定的設(shè)備。
接下來就來看看這個包的結(jié)構(gòu):

這個包分五個部分
- 第一個部分是命令標示符
- 第二個部分是我們的deviceToken的長度
- 第三個部分是我們的deviceToken字符串
- 第四個部分是推送的消息體(Payload)的長度
- 最后一個部分也就是真正的消息內(nèi)容了,里面包含了推送消息的基本信息。(比如消息內(nèi)容,應用icon右上角顯示的數(shù)字角標以及推送消息到達時所播放的聲音等)
接下來詳細看一下Payload(消息體)的結(jié)構(gòu)

Payload(消息體)其實就是個JSON結(jié)構(gòu)體。上面的圖只是簡單的一種消息體更多詳細類型的消息體類型,請看消息體蘋果官方相關(guān)介紹
- alert里的就是會顯示在用戶手機上的推送標題內(nèi)容
- badge顯示的數(shù)量(注意是整型)是會在應用icon右上角顯示的數(shù)量,提示有多少條未讀消息等
- sound就是當推送信息送達是手機播放的聲音,傳defalut就標明使用系統(tǒng)默認聲音,如果傳比如“xxx.wav”就會播放在我們應用工程目錄下名稱為xxx.wav的音頻文件,比如當手機鎖屏時QQ在后臺收到新消息時的滴滴聲。
安全架構(gòu)
為了保證安全性,APNs用連接信任(connection trust)和token信任(token trust)來控制通信入口,你要用APNs則必須用通過這兩種驗證。
連接信任
連接信任第一個作用是保證APNs連接的provider是蘋果已經(jīng)同意可通信的,然后第二個是保證與APNs連接的設(shè)備的合法性,第二步是APNs處理的,你所要處理的是provider與APNs之間的連接安全性。
服務器與APNs之間的連接信任
每個服務器都必須要有唯一的provider證書和私鑰,都是用來驗證連接的。provider證書就是在開發(fā)者官網(wǎng)申請的。
服務器通過TLS驗證和APNs連接,HTTPS中用的也是TLS協(xié)議,即四步握手,首先初始化TLS連接,即provider(服務器)發(fā)送請求給APNs,APNs服務器返回APNs證書(即公鑰)給provider,然后服務端收到后生成provider證書后再返回給APNs,APNs收到后驗證后即可以建立TLS連接,不過APNs用的不是HTTPS,而是HTTP/2,具體過程如下圖
APNs推送中的問題
問題一: 當應用從設(shè)備卸載后,推送的消息改如何處理??
我們知道當應用從設(shè)備卸載后,是收不到推送消息的。但是,如何讓APNs和Provider知道不再向這臺卸載了應用的設(shè)備推送消息呢?
針對這個問題蘋果也已經(jīng)幫我們解決了(那就是Feedback Service)。它是APNS的一部分,APNs會持續(xù)的更新Feedback service的列表,當我們的Provider將信息發(fā)給APNs服務器,APNs推送信息到我們的設(shè)備時,如果這時設(shè)備無法將消息推送到指定的應用(應用已經(jīng)刪除),就會向APNs服務器發(fā)送一個反饋信息,而這個信息就記錄在Feedback service中。按照這種方式,Provider應該定時的去檢測Feedback service的列表,然后刪除在自己數(shù)據(jù)庫中記錄的存在于反饋列表中的deviceToken,從而不再向這些設(shè)備發(fā)送推送信息。連接Feedback service的過程同樣使用長連接的方式,連接上后,直接接收由APNs傳輸給我們的反饋列表,傳輸完成后斷開連接,然后我們根據(jù)這個最新的反饋列表在更新我們自己的數(shù)據(jù)庫,刪除那些不再需要推送信息的設(shè)備的deviceToken。
從Feedback service讀取的數(shù)據(jù)結(jié)構(gòu)如下:

結(jié)構(gòu)中包含三個部分
- 第一部分是一個時間戳,記錄的是設(shè)備失效后的時間信息
- 第二個部分是deviceToken的長度
- 第三部分就是失效的deviceToken,我們所要獲取的就是第三部分,跟我們的數(shù)據(jù)庫進行對比后,刪除對應的deviceToken,下次不再向這些設(shè)備發(fā)送推送信息
問題二:iOS 重復推送之謎 文章地址
問題三:收不到 APNs 推送怎么辦?
- 首先要知道服務器推送成功,并不代表設(shè)備就能收到推送。服務器推送成功只是將消息交給了蘋果服務器而已,蘋果服務器還需要設(shè)備在線才能推送的。
- 其次 deviceToken 可能會在 APP 卸載重裝后發(fā)生變化,客戶端對此需要制定相應的匯報策略,以便服務器及時更新存儲的 deviceToken 。
客戶端只要能上報正確的 deviceToken 就可以說明客戶端實現(xiàn)沒問題了。否則檢查客戶端是否開啟了遠程推送通知服務,Bundle Identifier 是否與申請的推送證書匹配。 - 檢查服務器內(nèi)存緩存的 deviceToken 或者數(shù)據(jù)庫存儲的 deviceToken 是否與客戶端匯報的一致。
排查服務器配置的證書是否過期,是否與客戶端的 Bundle Identifier 匹配,或者是否勿用了其他類型的推送證書。
采用抓包工具(如 Wireshark )抓包分析,看看服務器是否將消息交給蘋果服務器,客戶端是否收到了相應的推送通知。
參考文檔:
國內(nèi) 90%以上的 iOS 開發(fā)者,對 APNs 的認識都是錯的
iOS 必知必會 - APNs篇
蘋果推送機制APNs(一)