iOS推送機制詳解

簡介

APNs 是 Apple Push Notification service 的簡稱 蘋果推送通知服務
為什么會有 APNs 沾鳄?
由于移動設備內(nèi)存稽屏、CPU耗溜、電量的局限性丹诀,iOS 不允許 APP 的進程常駐后臺(事實上可以申請后臺運行一段時間,最長約10分鐘)及塘。
當用戶主動殺掉APP或者APP進入后臺超過限定時長時,就意味著該APP進程的結(jié)束锐极。這很大程度保障了前臺APP的流暢性笙僚,也延長了手機的使用時長。這也是蘋果用戶體驗好的原因之一拌屏。但是這也意味著窝爪,服務器無法主動和用戶交互(如推送實時消息等)橄妆。為了解決這個限制,蘋果推出了APNs栋猖,允許設備和服務器分別與蘋果的推送通知服務器保持長連接狀態(tài)。
假如我們的蘋果設備(PC電腦汪榔、筆記本蒲拉、iPad、iPhone等)安裝了一個名叫XXX的應用揍异。那么我們具體是怎樣接收到推送通知的全陨?流程如下圖:


image.png

安全結(jié)構

APNs 采用雙層信任機制:連接信任 和 device token(設備令牌) 信任

連接信任:服務器(Provider)與 APNs 之間 | APNs 與設備之間

服務器與 APNs :有兩種方式建立連接信任

1.基于令牌(JWT: Json Web Tokens)的連接信任

Provider只需要提供一對公私鑰(私鑰Provider自己保存,公鑰蘋果保存),并使用其中的私鑰生成并加密JWT Token衷掷,每次向APNs請求推送的時候帶上這個Token即可辱姨。
image.png
  • 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)建)潮剪。

image.png

  • Provider通過TLS向APNs請求連接涣楷。
  • APNs向Provider返回一個APNs證書。
  • Provider需要把你之前從開發(fā)者帳戶中生成的證書發(fā)給 APNs
  • APNs 驗證服務器提供的證書是否正確抗碰,如果正確狮斗,則確定服務器與 APNs 的信任連接。此時服務器可以向 APNs 發(fā)送推送請求了弧蝇。
APNs 與每個設備之間的連接是自動建立的碳褒,這個過程中,不需要你的 app 做什么看疗。

每個設備都有一個加密的證書和私有密鑰沙峻,在設備激活的時候生成,并保存在設備的 keychain 中两芳,在設備激活的時候摔寨,APNs 根據(jù)設備的證書和密鑰驗證并授權與設備之間的連接。
image.png
  • 當設備啟動與 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ù)。過程如下圖:
image.png
  • 設備自動將用戶的UDID 和應用的 AppID發(fā)送到APNs菠齿,APNs返回一個deviceToken給iOS設備
  • 設備將deviceToken發(fā)送到自己公司的后臺服務器佑吝,用以保存;
  • 當后臺需要推送消息給用戶時绳匀,服務器將需要推送的消息和deviceToken傳輸給APNs芋忿;
  • APNs將消息推送給指定的deviceToken對應的手機;
  • 用戶接收消息疾棵;

接下來就來看看這個包的結(jié)構:

image

這個包分五個部分

  • 第一個部分是命令標示符
  • 第二個部分是我們的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é)構如下:

image

結(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 證書
image.png

image.png

APNs基于 HTTP/2 的新 APNs 協(xié)議服務推出時間:
image.png

新 APNs 協(xié)議仍然存在的問題:不能保證推送肯定到達手機。當 APNs 向你發(fā)送了多條推送缀旁,但是你的設備網(wǎng)絡狀況不好记劈,在 APNs 那里下線了,這時 APNs 到你的手機的鏈路上有多條任務堆積并巍,APNs 的處理方式是目木,只保留最后一條消息推送給你,然后告知你推送數(shù)懊渡。那么其他三條消息呢刽射?會被APNs丟棄。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剃执,一起剝皮案震驚了整個濱河市誓禁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肾档,老刑警劉巖摹恰,帶你破解...
    沈念sama閱讀 212,185評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異怒见,居然都是意外死亡俗慈,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,445評論 3 385
  • 文/潘曉璐 我一進店門遣耍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闺阱,“玉大人,你說我怎么就攤上這事舵变『ɡ#” “怎么了?”我有些...
    開封第一講書人閱讀 157,684評論 0 348
  • 文/不壞的土叔 我叫張陵棋傍,是天一觀的道長救拉。 經(jīng)常有香客問我难审,道長瘫拣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,564評論 1 284
  • 正文 為了忘掉前任告喊,我火速辦了婚禮麸拄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘黔姜。我一直安慰自己拢切,他們只是感情好,可當我...
    茶點故事閱讀 65,681評論 6 386
  • 文/花漫 我一把揭開白布秆吵。 她就那樣靜靜地躺著淮椰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上主穗,一...
    開封第一講書人閱讀 49,874評論 1 290
  • 那天泻拦,我揣著相機與錄音,去河邊找鬼忽媒。 笑死争拐,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的晦雨。 我是一名探鬼主播架曹,決...
    沈念sama閱讀 39,025評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼闹瞧!你這毒婦竟也來了绑雄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,761評論 0 268
  • 序言:老撾萬榮一對情侶失蹤夹抗,失蹤者是張志新(化名)和其女友劉穎绳慎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漠烧,經(jīng)...
    沈念sama閱讀 44,217評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡杏愤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,545評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了已脓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片珊楼。...
    茶點故事閱讀 38,694評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖度液,靈堂內(nèi)的尸體忽然破棺而出厕宗,到底是詐尸還是另有隱情,我是刑警寧澤堕担,帶...
    沈念sama閱讀 34,351評論 4 332
  • 正文 年R本政府宣布已慢,位于F島的核電站,受9級特大地震影響霹购,放射性物質(zhì)發(fā)生泄漏佑惠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,988評論 3 315
  • 文/蒙蒙 一齐疙、第九天 我趴在偏房一處隱蔽的房頂上張望膜楷。 院中可真熱鬧,春花似錦贞奋、人聲如沸赌厅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,778評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽特愿。三九已至仲墨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間揍障,已是汗流浹背宗收。 一陣腳步聲響...
    開封第一講書人閱讀 32,007評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留亚兄,地道東北人混稽。 一個月前我還...
    沈念sama閱讀 46,427評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像审胚,于是被迫代替她去往敵國和親匈勋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,580評論 2 349