簡介
APNs 是 Apple Push Notification service 的簡稱 蘋果推送通知服務
為什么會有 APNs 沾鳄?
由于移動設備內(nèi)存稽屏、CPU耗溜、電量的局限性丹诀,iOS 不允許 APP 的進程常駐后臺(事實上可以申請后臺運行一段時間,最長約10分鐘)及塘。
當用戶主動殺掉APP或者APP進入后臺超過限定時長時,就意味著該APP進程的結(jié)束锐极。這很大程度保障了前臺APP的流暢性笙僚,也延長了手機的使用時長。這也是蘋果用戶體驗好的原因之一拌屏。但是這也意味著窝爪,服務器無法主動和用戶交互(如推送實時消息等)橄妆。為了解決這個限制,蘋果推出了APNs栋猖,允許設備和服務器分別與蘋果的推送通知服務器保持長連接狀態(tài)。
假如我們的蘋果設備(PC電腦汪榔、筆記本蒲拉、iPad、iPhone等)安裝了一個名叫XXX的應用揍异。那么我們具體是怎樣接收到推送通知的全陨?流程如下圖:
安全結(jié)構
APNs 采用雙層信任機制:連接信任 和 device token(設備令牌) 信任
連接信任:服務器(Provider)與 APNs 之間 | APNs 與設備之間
服務器與 APNs :有兩種方式建立連接信任
1.基于令牌(JWT: Json Web Tokens)的連接信任
- Provider通過TLS向APNs發(fā)起請求。
- APNs返回一個證書給Provider戚嗅。
- Provier驗證這個證書雨涛。通過后枢舶,發(fā)送push數(shù)據(jù)并帶上JWT token。
- APNs驗證token替久,并返回請求的結(jié)果凉泄。
TLS:為了保證數(shù)據(jù)傳輸安全,在HTTP層與TCP層之間插入的一個安全校驗層
基于令牌的連接方式需要注意:應該定時更新token蚯根,token的有效期為1小時后众。
- 對于基于JWT的方式,能每次請求都創(chuàng)建新的token颅拦,盡量在一小時內(nèi)使用同一個token蒂誉。
- 不能頻繁的建立、關閉連接距帅,否則APNs會把這當做是黑客攻擊右锨,拒絕訪問。應該盡量將連接甭到眨活绍移,直到你認為這個連接接下來會長時間不使用為止。
- 當需要發(fā)送大量的推送數(shù)據(jù)的時候讥电,可以同時創(chuàng)建多個連接蹂窖,以改善性能。
- 當?shù)蹁N證書或者token時恩敌,應該關閉所有相關的連接恼策。
2.基于證書的連接信任
這種方式是指Provider可以采用一個唯一的證書以及一個加密的私鑰來與APNs交互,其中證書是由蘋果產(chǎn)生的(通過蘋果賬號登錄到developer account配置創(chuàng)建)潮剪。
- Provider通過TLS向APNs請求連接涣楷。
- APNs向Provider返回一個APNs證書。
- Provider需要把你之前從開發(fā)者帳戶中生成的證書發(fā)給 APNs
- APNs 驗證服務器提供的證書是否正確抗碰,如果正確狮斗,則確定服務器與 APNs 的信任連接。此時服務器可以向 APNs 發(fā)送推送請求了弧蝇。
APNs 與每個設備之間的連接是自動建立的碳褒,這個過程中,不需要你的 app 做什么看疗。
每個設備都有一個加密的證書和私有密鑰沙峻,在設備激活的時候生成,并保存在設備的 keychain 中两芳,在設備激活的時候摔寨,APNs 根據(jù)設備的證書和密鑰驗證并授權與設備之間的連接。- 當設備啟動與 APNs 的 TLS 連接時怖辆,信任協(xié)商開始(圖中頂部的箭頭)是复。
- APNs 將 APNs證書 返回給設備删顶。
- 操作系統(tǒng)驗證此證書后,它會向 APNs 發(fā)送設備證書(圖“設備證書”中的箭頭)淑廊。
- 最后逗余,APNs 驗證設備證書并建立信任(圖中底部的箭頭)。
設備token的生成與分發(fā)
什么是deviceToken 季惩?
deviceToken是一個APP裝在一個設備上的唯一標識符录粱。一個APP在不同的設備上deviceToken不一樣;一個APP刪除之后再次安裝deviceToken也不一樣画拾。
在項目代碼AppDelegate里面有一個回調(diào)方法关摇,當APNs注冊成功通過該回調(diào)方法可以獲取到返回的deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
上面說過當有消息需要被推送時,我們自己的服務器會將消息按指定的格式結(jié)合設備的deviceToken一并打包 碾阁,APNs拿到這個包之后驗證這個包結(jié)構是否正確并提取其中的信息后,再將消息推送到指定的設備些楣。
在app啟動的時候脂凶,必須向iOS系統(tǒng)注冊遠程推送,成功后愁茁,蘋果將會返回一個設備token給app蚕钦,此時app就可以將這個token上報給自己的后臺。
如果有必要產(chǎn)生一個新的token鹅很,APNs會使用設備證書生成一個token(其中包含了一個設備ID)嘶居,并使用token key加密后返回給設備。同時設備會將這個token以NSData對象的形式返回給app促煮,app獲取到該token之后應該將其發(fā)送到自己后臺邮屁,后臺之后就可以通過這個token來發(fā)送推送數(shù)據(jù)。過程如下圖:- 設備自動將用戶的UDID 和應用的 AppID發(fā)送到APNs菠齿,APNs返回一個deviceToken給iOS設備
- 設備將deviceToken發(fā)送到自己公司的后臺服務器佑吝,用以保存;
- 當后臺需要推送消息給用戶時绳匀,服務器將需要推送的消息和deviceToken傳輸給APNs芋忿;
- APNs將消息推送給指定的deviceToken對應的手機;
- 用戶接收消息疾棵;
接下來就來看看這個包的結(jié)構:
這個包分五個部分
- 第一個部分是命令標示符
- 第二個部分是我們的deviceToken的長度
- 第三個部分是我們的deviceToken字符串
- 第四個部分是推送的消息體(Payload)的長度
- 最后一個部分也就是真正的消息內(nèi)容了戈钢,里面包含了推送消息的基本信息。(比如消息內(nèi)容是尔,應用icon右上角顯示的數(shù)字角標以及推送消息到達時所播放的聲音等)
當應用從設備卸載后殉了,推送的消息改如何處理?拟枚?
我們知道當應用從設備卸載后宣渗,是收不到推送消息的抖所。但是,如何讓APNs和Provider知道不再向這臺卸載了應用的設備推送消息呢痕囱?
Feedback Service田轧。它是APNS的一部分,APNs會持續(xù)的更新Feedback service的列表鞍恢,當我們的Provider將信息發(fā)給APNs服務器傻粘,APNs推送信息到我們的設備時,如果這時設備無法將消息推送到指定的應用(應用已經(jīng)刪除)帮掉,就會向APNs服務器發(fā)送一個反饋信息弦悉,而這個信息就記錄在Feedback service中。按照這種方式蟆炊,Provider應該定時的去檢測Feedback service的列表稽莉,然后刪除在自己數(shù)據(jù)庫中記錄的存在于反饋列表中的deviceToken,從而不再向這些設備發(fā)送推送信息涩搓。連接Feedback service的過程同樣使用長連接的方式污秆,連接上后,直接接收由APNs傳輸給我們的反饋列表昧甘,傳輸完成后斷開連接良拼,然后我們根據(jù)這個最新的反饋列表在更新我們自己的數(shù)據(jù)庫,刪除那些不再需要推送信息的設備的deviceToken充边。
從Feedback service讀取的數(shù)據(jù)結(jié)構如下:
結(jié)構中包含三個部分
- 第一部分是一個時間戳庸推,記錄的是設備失效后的時間信息
- 第二個部分是deviceToken的長度
- 第三部分就是失效的deviceToken,我們所要獲取的就是第三部分浇冰,跟我們的數(shù)據(jù)庫進行對比后贬媒,刪除對應的deviceToken,下次不再向這些設備發(fā)送推送信息
deviceToken注意:不是設備唯一標識肘习,是設備和應用組合的唯一標識掖蛤。同一個手機不同的應用會生成不同的deviceToken,同一個手機同一個應用只生成一個deviceToken井厌。在iOS7.0和iOS8.0的系統(tǒng)中蚓庭,卸載重裝應用,deviceToken不會發(fā)生變化仅仆,但是iOS9.0(包括)以后卸載重裝應用器赞,deviceToken會發(fā)生變化。
服務器的職責
服務器在跟 APNs 溝通連接的時候具有以下責任:
- 通過 APNs 接收并管理關于你的app的全球唯一的設備驗證碼墓拜,及其它一些數(shù)據(jù)
- 根據(jù)app功能的需要港柜,決定通知推送的時間
- 建立通知請求,并發(fā)送通知請求到 APNs, APNs 再將通知遞送到相應的設備
推送內(nèi)容:
遠程推送通知夏醉,分為 普通推送 / 后臺推送 / 靜默推送 3 種類型
- 普通推送
- 就是我們在手機上平時見到的推送通知爽锥。
- 包含聲音、橫幅畔柔、角標氯夷、自定義字段。
- 處于前臺靶擦,不會展示橫幅腮考,可通過 didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after)獲取通知內(nèi)容(前臺展示橫幅的方法看這里)。
- 處于后臺玄捕,會展示橫幅踩蔚,無法獲取通知內(nèi)容。
- 處于退出枚粘,會展示橫幅馅闽,無法獲取通知內(nèi)容。
- 點擊圖標啟動馍迄,無法獲取通知內(nèi)容福也。
- 點擊通知橫幅啟動,在 didFinishLaunchingWithOptions 獲取通知內(nèi)容柬姚。
{
aps = {
alert = "顯示內(nèi)容";
badge = 1; // App 角標, 1)當badge>0時庄涡,角標會隨badge而變化量承。2)當badge=0時,角標維持不變穴店。3)當badge<0時撕捍,角標維持不變。
sound = default; // 推送聲音泣洞,默認系統(tǒng)三全音忧风,如需使用自己的聲音,需要將聲音文件拖拽&拷貝至 Xcode 工程目錄任意位置球凰,并在推送時指定其文件名
};
key1 = value1; // 自定義字段狮腿,可設置多組,用于處理內(nèi)部邏輯
key2 = value2;
}
- 后臺推送
- 各種顯示效果跟普通推送完全一樣呕诉。
- 必須攜帶 "content-available" = 1;
- 必須攜帶 alert缘厢、badge、sound 中 至少 1 個字段甩挫。
- 僅 iOS 7 以后支持贴硫。
- 必須在 Xcode 工程中 TARGETS – Capabilities – Background Modes – Remote notifications 開啟該功能,具體可參照 iOS 7 Background Remote Notification。
- 處于前臺英遭,可通過didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after) 獲取通知內(nèi)容间护。
- 處于后臺,可通過 didReceiveRemoteNotification:fetchCompletion Handler: 獲取通知內(nèi)容 // 獲取情況中與普通推送的唯一不同點挖诸,此時 iOS 系統(tǒng)允許開發(fā)者在 App 處于后臺的情況下汁尺,執(zhí)行一些代碼,大概提供幾分鐘的時間税灌,可以用來偷偷的刷新 UI均函、切換頁面、下載更新包等等操作菱涤。
- 處于退出苞也,無法獲取通知內(nèi)容。
- 點擊圖標啟動粘秆,無法獲取通知內(nèi)容如迟。
- 點擊推送橫幅啟動,在 didFinishLaunchingWithOptions 獲取通知內(nèi)容攻走。
{ aps = { alert = "顯示內(nèi)容"; badge = 1; "content-available" = 1; // 必帶字段 sound = default; }; key1 = value1; }
- 靜默推送
- 沒有任何展示效果殷勘。
- 必須攜帶 "content-available" = 1;,因此靜默必然是后臺的昔搂。
- 必須不攜帶 alert玲销、badge、sound摘符。
- 可攜帶自定義字段贤斜。
- 處于前臺,可通過didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after) 獲取通知內(nèi)容逛裤。
- 處于后臺瘩绒,可通過 didReceiveRemoteNotification:fetchCompletion Handler: 獲取通知內(nèi)容 // 獲取情況中與普通推送的唯一不同點,此時 iOS 系統(tǒng)允許開發(fā)者在 App 處于后臺的情況下带族,執(zhí)行一些代碼锁荔,大概提供幾分鐘的時間,可以用來偷偷的刷新 UI蝙砌、切換頁面阳堕、下載更新包等等操作。
- 處于退出择克,無法獲取通知內(nèi)容嘱丢。
{
aps = {
alert = "";
"content-available" = 1; // 必帶字段
};
key1 = value1;
}
新舊協(xié)議:基于二進制的舊 APNs 協(xié)議、基于 HTTP/2 的新 APNs 協(xié)議:
新舊協(xié)議的對比:
舊協(xié)議 | 新協(xié)議 |
---|---|
連接不穩(wěn)定 | 長連接祠饺,提供檢測是否可用的方法 |
發(fā)送給APNs成功沒有相應 | 成功失敗均有相應 |
最大支持256字節(jié) | 最大4k |
- | Request 和 Response 支持JSON網(wǎng)絡協(xié)議 |
不同的推送越驻,需要配置不同的推送證書 | 不同推送類型,只需要一種推送證書 Universal Push Notification Client SSL 證書 |
新 APNs 協(xié)議仍然存在的問題:不能保證推送肯定到達手機。當 APNs 向你發(fā)送了多條推送缀旁,但是你的設備網(wǎng)絡狀況不好记劈,在 APNs 那里下線了,這時 APNs 到你的手機的鏈路上有多條任務堆積并巍,APNs 的處理方式是目木,只保留最后一條消息推送給你,然后告知你推送數(shù)懊渡。那么其他三條消息呢刽射?會被APNs丟棄。