IOS的APNS和PushKit門道詳述

基本功

iOS在誕生之初爲了最大程度的保證用戶體驗,作了一些高瞻遠矚且影響深遠的設計。APNs(Apple Push Notification service)就是其中一項。 

早期iOS設備的內存和CPU資源都頗有限,爲了讓前臺活躍的app擁有儘量多的系統資源,以及節約設備電量,iOS一開始就「不容許」普通app的進程常駐後臺。這個決定很大程度上保障了用戶體驗和延長了手機的待機時間,但app的開發商須要和他們的用戶保持聯繫。開發商須要有一個穩定的網絡通道能每隔一段時間推送新的內容到用戶設備。Apple決定本身來搭建維護這個通道,也就是咱們今天所說的APNs。記得剛開始接觸iOS開發的時候,看到有很多開發者吐槽push機制,以爲不可控且增長了開發成本。其實稍微思考下Apple今天的平臺規模和消息量,以及所帶來的成本消耗,就能明白Apple設計這個機制所須要的智慧和魄力。一切都是爲了用戶。 

APNs雖然容許開發商推送消息到用戶設備,但考慮到消息的量級和成本,這個由Apple維護的長連接通道就不多是無限制使用的。APNs有着諸多的限制: 

可靠性。通常狀況下,Apple會保證這個通道的Qaulity of Service,也就是推送的消息能及時穩定到達設備。不過一旦用戶的設備處於offline狀態,Apple只會存儲發送給用戶的最新一條push,以前發送的push會被直接丟掉。並且這最後一條離線push也是有過時時間的。一些用戶應該有過這種經歷,在使用微信的時候,明明對方發送了多條消息,卻只收到了一條push。 

Payload Size。每一條push消息的包體大小是有最大限制的。Apple在文檔裏清楚的說明,push只應該用來通知用戶有新的內容,而不該該用來承載內容自己。理論上payload size越小,push到達設備的機率就越高。在iOS8以前max payload size是256字節,到iOS8發佈這個最大值被調整到了2048字節,再到最近的iOS9發佈,引入了HTTP2.0,payload size又被設爲4KB了。老版本的256字節實在有點捉襟見肘,連塞一個連接進去都要考慮再三。到2KB的時候就寬裕多了,已經有很多開發商開始嘗試往裏面放少許的業務數據了,若是能減小打開app以後的一次網絡請求何樂而不爲呢。固然4KB的想象空間會更大。Apple一直在調整這個數值,爲的是給開發商更多的空間去提高用戶體驗。push慢慢變的不只僅是一條「alert」那麼簡單了。 

成功率並不高。Apple雖然保證了push通道必定程度的可靠性,但push因爲各類各樣的緣由並不能保證較高水平的到達率。push須要向用戶申請權限,即便當時賦予了權限,後面也可能因爲push過於頻繁被用戶又關掉。在夜間模式下push雖然能到達通知欄,可用戶沒有任何感知,更不用說點擊push啓動app了。還有server端token失效,這點能夠經過feedback service來清理失效的token。Apple的APNs server聽說天天會發送超過百億條push,在某個時間段出現峯值的時候,開發商server和Apple server鏈接的成功率也會下降。還有客戶端設備所處網絡環境並不穩定等等因素,使得經過push成功啓動app的成功率並不怎麼高。 

理解了上面這些限制,就能按照Apple的規範向用戶推送內容了。但push裏面的門道遠不止這麼簡單,Apple也從沒有中止過對APNs體驗的優化,相似payload size調整,interactive notification等等,每個新的feature增長,哪怕是細微的改動,都能被聰明的開發者加以利用,以四兩撥千斤提高產品的體驗。下面就介紹一些筆者所瞭解到的「隱蔽門道」。html



不只僅是Local Push

不少我的開發者不具有搭建server的條件,通常會設置一個定時的local push來提醒用戶喚醒本身的app。Local push看起來彷佛是個廉價的折中方案,事實上它能夠更強大。APNs(通常也叫作remote push)由於有上面的各類限制,並不能很好的契合業務須要。而Local Push則不一樣,擁有完整的app業務上下文,還能夠對push進行定製化。若是能夠用Local Push替代Remote Push對體驗的提高是不言而喻的。Loca push的限制在於app必須處於運行狀態才能發起,不少聰明的開發商會開啓background task,在用戶按了home鍵以後再爭取到幾分鐘的運行時間,在這期間全部的remote push都被替換成了local push。不要小看了這幾分鐘的時間,對於不少活躍度高的app來講,按home鍵以後立刻又產生新的用戶內容的機率並不小。微信,WhatsApp都採用了這種機制來提高體驗。ios



叫醒你的App

開啓background task以後雖然可以再多運行一會,但時間一到,app仍是會被掛起或者kill。大部分多時候你的app是處於非活躍狀態。不少app都須要預先獲取內容,或者後臺下載文件等來減小用戶的等待時間。iOS7引入的Silent Notification和Background Fetch機制能夠必定程度上知足這種須要。silent push實現比較簡單,開啓相關後臺權限以後發送以下特定格式的json就能啓用。git

喚醒app以後能處理的業務就多了,這對很多app來講是個很是實用的拓展,預加載內容也好,生成local push也好,都能提高體驗。但這種喚醒機制並不老是可靠,有時候會「叫不醒」。app若是被手動kill叫不醒,若是background fetch被用戶關閉也叫不醒,但這兩種狀況在手機充電的時候又能夠被叫醒。Apple有一套本身的「智能」策略。github



前臺消息通道

大部分時候APNs都被用來通知用戶某個處於background的app有新內容。但其實說白了APNs不過就是一條基於長連接的數據通道,在app處於foreground的時候也是能收到push消息的,不過不會有任何UI展現提醒而已。處理回調的位置也是在 也就是說APNs其實仍是個免費的前臺消息通道。並且有時候走APNs通道會比本身的server通道更快,若是客戶端作好數據去重,多一個輔助的數據通道固然能提高體驗。json



新神通PushKit

APNs設計的初衷是避免app常駐後臺,只在用戶點收到push的時候主動去啓動app。前面提到的silent push能夠在有限的場景下,無需用戶感知啓動app。但到iOS8引入PushKit framework以後,app就能夠經過push隨時喚醒了,不過這個新的神通暫時還只限於voip類應用。服務器

以前在社區看到有人提問,說微信電話本能夠在用戶掛掉電話的時候,把呼叫中的push改爲未接電話,好奇是怎麼辦到的。由於你們都知道remote push是沒法經過server動態修改push內容的,因此答案只有一個可能,app被後臺喚醒了。用戶看到的push實際上是local push,而local push是能夠在客戶端隨意調整的。喚醒到方式就是利用PushKit。微信

固然好處不只僅是修改push內容這麼簡單。WhatsApp的用戶在iOS8以後應該會有明顯的感受,好像不多看到啓動頁面了。看起來彷佛是WhatsApp開啓了voip後臺常駐運行模式,但這種模式會比較費電,一些用戶會有顧慮。真相也並不是如此,WhatsApp並無常駐後臺,只不過是開啓了PushKit的push喚醒機制。每次用戶有新的離線消息,普通文本或者是voip call,app都會先被後臺喚醒,再從server拉取離線消息,最後生成local push。等用戶點擊local push啓動app的時候,沒有啓動頁面,沒有connecting和loading,全部的數據已經準備就緒,就好像WhatsApp一直在後臺運行同樣。也就是說,WhatsApp其實已經把全部的push都換成了local push。驗證方法也很簡單:網絡

  • 手動kill WhatsApp。
  • 手機進入飛行模式。
  • 收一條離線消息。
  • 使用tcpdump開始監聽iphone網絡包,關閉飛行模式。
  • 這時候,app被push喚醒,能看到以下圖一條WhatsApp相關的域名解析,說明app被啓動了。並且能看到不少後續的服務器交互(拉取離線消息之類)。  2 微信不知道是出於什麼考慮,既沒有開啓voip後臺常駐模式,也沒有利用PushKit喚醒機制。每次收到消息以後打開app,都是先看到地球,鏈接中,收取中,到真正看到最新消息常常須要3s以上。PushKit已經沒有電量方面的額外損耗了,對voip類應用的體驗提高很是之大。

具體怎麼實現PushKit能夠參照文章末尾的連接地址。app



總結

關於push這條長連接通道,Apple幾乎在每次的iOS新版本里都會增長一些feature。爲了控制新feature帶來的影響,每次改動都很少,但怎麼利用這些feature就看開發者各自都功力了。對用戶體驗帶來的改變遠不止官方文檔上介紹的那麼簡單,只有多思考,時刻關注行業最新動態,才能發掘更多的隱藏「門道」。iphone



參考文章

  1. Apple APNs官方文檔:https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html
  2. Silent Push實現:http://hayageek.com/ios-silent-push-notifications
  3. PushKit實現:https://zeropush.com/guide/guide-to-pushkit-and-voip

來自: http://music4kid.github.io/ios/2016/01/06/push/

 

感謝:http://www.open-open.com/lib/view/open1452487743355.html

相關文章
相關標籤/搜索