說Android端外推送比較煩,實際有兩層意思:首先是說實現上比較麻煩,至今業界也沒有找到一種完美的解決方案,Android程式設計師通常需要同時整合多家推送平臺(如果有自己的端內推送,還要考慮與端內推送的配合);其次是說Android推送的市場現狀比較混亂,無論選擇哪一家,都讓人糾結萬分,難免心情煩躁。無論是你花費了多少功夫,做了多少優化,仍然可能存在推送不到或推送延遲的情況。
網上已經有很多關於Android推送的討論,但很少有站在App開發者(特別是開發App的創業團隊)的角度來進行介紹的文章。本文的目的,就是站在一個App開發團隊的角度,集中討論兩方面的問題:
- 如何對各家的推送平臺進行技術選型;
- 在整合各家推送平臺的SDK的時候,應該重點關注哪些問題。
為什麼本文只討論端外推送?
通常大廠的App都會區分端內推送和端外推送(端指的是客戶端),具體說來:
- 當App在前臺執行的時候,這時的推送稱為端內推送。端內推送一般是走App自己實現的一套推送系統:推送伺服器是自己的,客戶端維護一條長連線連到自己的推送伺服器,不依賴任何第三方的推送系統。
- 當App從前臺退到後臺,在短時間內App未被殺死前,App自己的長連線仍然有效。這時的推送可以仍然走App自己的推送系統。所謂的“Android程式保活”,就是為了儘量延長這段在後臺存活的時間。
- 當App在後臺執行足夠長的時間後,App程式由於被清理或者其它原因,App自己的長連線斷開。這時的推送就稱為端外推送了,只能走某個第三方推送平臺了。
從這個過程來看,大廠的App的推送策略可以概括為:優先使用自己的推送,實在不行再走第三方推送平臺。為什麼這樣呢?因為自己的推送系統更快、更有保障:
- 更快,是因為你交給第三方推送平臺的推送訊息要跟很多其它家App的訊息一起排隊。如果某家App突然在短時間內傳送大量推送訊息給推送平臺(推廣活動,或者程式bug),那麼這個推送平臺上的其它App就有可能受到牽連,推送延遲變得很大。這樣的情況是很可能會發生的。比如,在某個推送平臺的技術交流群裡,不定期地就會看到有人在喊:“是不是推送又堵了啊......”
- 更有保障。大廠通常有專門的隊伍維護推送相關的服務,有問題可以快速推進優化。
我們雖然算不上大廠,但我們維護的微愛App也是有自己獨立的端內推送的,而端外採用另外幾家推送平臺,後面我們再詳細講。
那為什麼本文只討論端外推送呢?因為討論端內推送和討論端外推送是完全不同的兩個話題。討論端外推送,我們主要是在討論怎麼對各家的推送平臺進行選擇,以及整合各家SDK的時候我們應該重點注意哪些問題。這通常是很多初創團隊更需要的。
而討論端內推送,主要應該討論一個推送系統的具體實現,這是一個比較複雜的問題,並不是一篇文章就能討論清楚的。在這裡,我們只是浮光掠影地瀏覽一下這個話題可能涉及到的內容,但不做展開討論:
- 採用什麼協議?XMPP還是MQTT還是自定義二進位制協議?是否像微信一樣,需要推送二進位制資料(比如短語音和縮圖資料)?
- 如何保證後臺長連線不死?涉及到“保活”的問題。
- 如何做才能真正保證不丟資料?涉及到系統的方方面面,比如訊息的確認,客戶端和伺服器的資料同步,客戶端的資料儲存的事務保證,後臺訊息佇列如何設計保證不丟資料。如果是IM,離線資料如何處理?
- 長連線的Keep Alive和連線狀態的檢測與維護。比如XMPP相當於一個永遠解析不完的XML流,使用一個空格作為Keep Alive訊息。
- 長連線的安全性。驗證以及加密。
綜上,本文要討論的重點是端外推送。
有哪些推送平臺可以選擇?
端外推送我們必須依賴第三方的推送平臺了。
這個情況其實本來跟iOS上類似。在端內推送系統的長連線失效的時候,我們就只能通過其它的推送平臺來完成。在iOS上我們只用使用APNs就行了。
而在Android上,跟APNS對應的服務是谷歌的GCM (Google Cloud Messaging),但很可惜它在國內的可用性不高(主要原因是手機廠商對Android系統的定製化,可能會將GCM服務裁減掉,以及國內運營商的一些限制)。如果我們做的是一個海外的應用,那麼端外推送基本只用考慮GCM就可以了。
那國內的Android推送平臺有哪些可以選擇呢?
根據我個人瞭解到的資訊,我列出了下面這些(排名不分先後):
- 小米推送(MiPush)
- 華為推送(華為Push)
- 友盟推送(U-Push)
- 個推
- 極光推送
- 阿里雲移動推送(Alibaba Cloud Channel Service)
- 騰訊信鴿推送
- 百度雲推送
我們選的是哪家推送?選擇標準是什麼?
上面提到的各推送平臺大體可以分為三大類:
- 大手機廠商的推送:小米推送、華為推送。
- 專業的第三方推送:友盟推送、個推、極光推送
- BAT大廠的平臺推送:阿里雲移動推送、騰訊信鴿推送、百度雲推送。
要對這些推送平臺進行選擇,我們首先要知道各類推送平臺的優勢分別是什麼。
首先,對於手機廠商的推送,他們的推送服務在他們自己生產的手機上屬於系統級別的服務,理論上來說,手機系統對他們自家的推送限制最小。
比如,在小米手機上,不在系統自啟動名單裡的App,在手機重啟後,App宣告的後臺Service並不會自動執行。但是,小米推送作為手機系統級服務,仍然是可以收到推送的。
同樣,華為推送的技術團隊也對外宣稱(原話):
華為Push,在華為手機上是系統級別的服務,穩定性等各方面肯定都會好些。
但是,即使是系統級別的推送服務,也不是百分百保證訊息送達。這裡比較奇葩的是華為推送,下面是他們技術支援給出的描述(原話):
華為手機上:
Emui3.0上,Push廣播有很大概率被限制,如: Mate7 3.0版本,榮耀6plus,P7 3.0版本,4X, 4A等。
Emui3.1上,Push廣播基本不被限制,但個別型號機型存在問題,如:榮耀5x等。
Emui4.0及以上,Push廣播有較高概率被限制,不被限制的機型如:榮耀暢玩4C,榮耀暢玩4X,Mate S,P8 MAX等。
如廣播被限制,需要將應用設為開機啟動項。所以對於及時性或到達率要求非常高的應用,我們建議應用要考慮替代方案。
後續Push版本,華為將採用新的設計方案,解決被限制的問題,但釋出計劃待定。另外,至於限制的問題,其實華為sdk還是能接收到推送訊息的,當將訊息通過廣播傳送給應用是,如果手機管家查到該應用處於stop狀態,那麼會攔截該廣播的。
看完之後的感覺:還真他媽複雜!
總之,華為手機上的推送,華為推送自己也不太完全能搞得定的。但是,我們考慮再三,似乎也沒有更好的選擇了。
再說第二類:專業的第三方推送。他們的優勢看什麼呢?看他們“保活”和“互拉”的能力。舉個例子,假設你接入了友盟,而恰好今日頭條也接入了友盟。有一天你的App被殺死了,但是今日頭條的裝機量估計比你的要大啊,這時使用者啟動了今日頭條,那麼推送系統也就會通過共享的推送通道順便把你推送訊息送達到手機上,然後還可能把你的程式也喚醒(被“保活”了)。
這麼說來,選第三方推送平臺,這個推送平臺的規模效應就很重要了。那如何得知他們的規模和市場份額呢?最好的辦法是問內部的朋友。否則,其實也沒什麼好的辦法,每家肯定對外都說自己最好啊。有一個不太精準的方法,就是看他們的合作客戶裡有哪些大的app,到他們官網上的合作案例裡去看。這個資訊總不能亂寫把。
而對於BAT大廠的推送呢?看起來並沒有什麼優勢。各家的“全家桶”採用的“保活”陣營和推送通道,跟他們開放出來的是兩碼事。比如,你不要以為用了騰訊信鴿推送,就能占上微信的光。
這裡需要單獨提一下的是阿里雲的移動推送。在他們官網上提到,手機淘寶就是用了阿里雲的這個推送。不過仔細研究一下會發現,手機淘寶也在同時使用其它的第三方推送平臺啊(比如友盟推送)。兩個平臺到底誰借誰的力更多呢?不得而知啊。
綜合上面的分析,我們在微愛的Android客戶端裡使用的推送方案基本如下所述:
- 端內使用微愛自己的推送;
- 端外在小米手機上使用小米推送;
- 端外在華為手機上使用華為推送;
- 端外在其它手機上統一使用一種推送,也就是上面推送平臺列表中的某一個。具體是哪個就不說了,本文中我們稱它為X-Push吧。
注意:小米推送在非小米手機上當然也能工作,只不過就不是系統級別的服務了,受的限制就多一點。同理,華為手機也一樣。我們之所以這樣選擇,是為了讓不同的推送執行在各自擅長的環境裡。
基本的架構圖如下:
本來呢,對於推送平臺的選擇問題,到這裡就應該結束了。但是,最近發生了一件事,讓我們覺得被X-Push這家坑了一把,這讓我們突然意識到了一個選擇陷阱。現在把它分享出來,好讓大家選擇的時候一定要擦亮眼睛。
事情大致經過是這樣的:我們開始整合X-Push這家推送的時候,使用的是免費版服務。但是,我們用了一段時間之後,他們的銷售找了過來。宣稱他們SDK裡的“看護功能”,是付費功能,如果不付費,技術那邊就會通過一些操作關閉這一功能。這裡他們提到的“看護功能”,大概就是本文前面提到的“保活”和“互拉”的能力。
這個事情的關鍵點在於什麼呢?
- 我們一直以來都認為對於這類第三方推送平臺,“看護功能”是他們最基礎的一個功能。我們在整個接入開發的過程中,沒有從任何來源得到關於“看護功能”要單獨收費的說明。他們官網上的公開價格表壓根沒有提到這個功能,接入的技術支援QQ群裡也沒有任何人提到過,官方的開發文件更是無處提及。
- 我們在整個接入和測試的過程中,以及後來上線之後執行的這段時期內,這個“看護功能”都是一直包含在SDK內的。等用了一段時間之後,卻突然被告知這一基礎功能要收費,實在讓人措手不及。
- 如果明碼標價,我們在最開始選型的時候就會把這一因素考慮進去。但是該平臺卻在開始的時候故意隱藏可能存在的收費陷阱。
- 對方稱如果被關閉了“看護功能”,那麼“訊息觸達效果”會有明顯地降低。我們也能理解“免費+收費”的商業模式,但是通常來講,這種模式是對於基礎功能免費,而對於高階功能收費,很少見到以降低服務質量作為免費條件的。
如果把這件事的全部細節寫出來,恐怕還需要額外的5000字。由於本文的主要目的還是分享技術選型的經驗,所以這裡點到為止,能把事情的大致經過說清楚就好了。等這件事塵埃落定以後,我們也許還有機會再重新拿出來講一講這個故事。
但是,這裡你要記住的是,在你選擇一家推送平臺之前,一定要找人問清楚對方收費的模式,有沒有隱性的消費陷阱。記住:沒有人主動會告訴你喲。
大家也別問這家X-Push到底是哪家了,大家自己去體會。這裡能起到提醒的作用就夠了。
你是否需要自己的端內推送?
對於小的創業團隊來說,自己實現端內的長連線推送系統,成本還是不小的。
其實呢,各個第三方推送平臺也是可以在端內使用的。而且,他們一般也對iOS的APNs推送也有封裝。所以,在資源緊缺的情況下,小團隊在初期也可以選擇某家第三方推送平臺做自己全部的推送服務,能快速地同時支援Android和iOS兩個平臺推送。等後邊人手充裕了,再考慮進行優化,或加入新的推送渠道。
具體怎樣選擇,還在於你自己權衡。
使用通知欄訊息還是透傳訊息?
通常第三方推送平臺都支援兩種推送訊息型別:通知欄訊息和透傳訊息。
通知欄訊息,在被送達使用者的裝置後,直接以系統通知的形式展示給使用者。它不會繼續被傳遞到App。
而透傳訊息,在被送達使用者的裝置後,還會繼續路由到App,通過回撥App的某個BroadcastReceiver的形式將訊息傳遞到App內部。然後由App決定如何處理和顯示這個訊息。
這兩類訊息在送達率的保證上有所不同,當然在提供的程式設計能力上也非常不同。
透傳訊息在整個訊息傳遞過程中比通知欄訊息多了一步,因此就增加一些被系統限制的概率。所以說,通知欄訊息比透傳訊息應該能提供更好的送達率。
比如,小米推送的文件中就這樣描述:
在一些 Android 系統(如 MIUI)中,受到系統自啟動管理設定的限制,應用不能在後臺自啟動。在這類系統中,如果在傳送訊息的時候對應的應用沒有被啟動,透傳類訊息將不能順利送達。因此,對於對送達率要求很高的訊息,建議儘量採用通知欄提醒的方式推送訊息
如果App有自己的端內推送系統,那麼這種通知欄推送訊息就更合適一些。當端內推送的長連線失效時,我們通過通知欄訊息把提醒展示給使用者,由使用者喚起我們的App,然後真正的訊息資料再經由端內推送達到客戶端。
實際上,我們就是採用通知欄訊息這種推送方式的。
而透傳訊息,提供了對訊息資料的更靈活的操縱能力。App如果僅僅通過通知欄訊息,是無法接觸到訊息資料本身的。
所以,如果App沒有自己的端內推送系統,而是採用第三方推送作為端內推送通道,那麼就只能使用透傳訊息。
另外一個例子,如果App想自定義通知提醒的樣式,以及提示聲音,恐怕也只能通過透傳訊息來自己實現。通知欄訊息通常提供不了那麼靈活的配置。
這裡有一點需要說明的是,當透傳訊息送達裝置後,如果在試圖路由到App內部的時候,發現App程式不在,那麼理想情況下它應該“拉起”App程式。所以,照此推測,如果前面提到的那家X-Push關閉了“看護功能”的話,那麼透傳訊息會受到多大的影響呢?結果可想而知。另外,X-Push那家的銷售說了,關閉“看護功能”,對通知欄訊息的“訊息觸達效果”也是有影響的。無語......
推送的初始化和推送token的同步
我們使用第三方推送平臺,最關鍵的地方在於前兩個步驟:
- 在恰當的時機把推送SDK初始化起來。
- 初始化之後App會非同步地收到一個推送token,那麼接下來需要把這個推送token同步到App伺服器。
這裡的推送token,在不同的推送平臺上的叫法不太一樣,比如在小米推送中被稱為reg id,在華為推送中被稱為token,在個推中被稱為cid,在友盟推送被稱為Device Token。總之,它是推送平臺對裝置的唯一標識。我們這裡統稱它為“推送token”是為了方便討論。
App的客戶端拿到它之後,必須要同步到自己的伺服器,並與自己的使用者ID建立起對應關係。這樣當我們想推送訊息給我們的某個使用者的時候,我們才能查到對應的推送token。
前面說的初始化和推送token同步這兩個步驟,看起來很簡單,只是呼叫SDK的現成介面,再把它傳送給伺服器而已。但是,好的程式碼不僅能在正常情況下工作,還應該充分考慮失敗情況。有什麼樣的失敗情況需要我們考慮呢?我們以小米推送為例來分析一下:
- 小米推送要求在Application物件的onCreate中執行初始化操作。我們可以猜測一下,在這個初始化操作中小米推送的SDK可能需要在本地為我們修改配置,還可能需要聯絡小米推送的伺服器來申請reg id(即推送token)。這個初始化過程是可能失敗的,本地操作可能會受到系統的限制,網路更是可能出錯。試想,如果初始化出錯了,我們還會收到推送token嗎?
- 假設我們成功收到了推送token(通常在一個BroadcastReceiver中),接下來把推送token傳送到我們自己的伺服器,這個工作需要我們自己來完成了。我們都知道在移動環境下網路很可能是弱網環境,這次同步如果失敗了,那麼下次要等到什麼機會才能再次進行同步呢?
上述第一種初始化錯誤,理應由推送SDK來處理。如果失敗,它應該會有重試機制,直到成功獲取了推送token,它再重新呼叫App把推送token傳過來。比如,小米推送平臺也是這麼宣稱的,初始化可能出現的錯誤,App開發者不用考慮。如果你充分信任推送平臺,那麼這個錯誤其實是可以不用去考慮的;否則,你可以在App裡增加某些機會來檢測初始化是否已經成功(可以通過檢測是否已經拿到推送token來確定),然後在恰當的時機重新呼叫初始化程式碼。當然,在做這個事情之前,你最好與推送平臺溝通清楚,確保重複呼叫初始化程式碼不會產生什麼副作用。
上述第二種錯誤,就必須靠App開發者自己處理了。這裡我們實際上需要在App客戶端和伺服器之間抽象出一條強的通訊通道,我們把同步推送token的請求放進去,這條通訊通道能夠在失敗發生的時候自動重試。
這裡的程式碼寫得是不是足夠健壯(robust),不同level的程式設計師就高下立判了。
我們可以說,恰當而全面地處理失敗情況才能真正體現工程師的意義,這也是工程和理論研究的不同點之一。
推送的送達率到底跟什麼有關?
推送做得好不好,以及我們選擇推送平臺選的好不好,關鍵在於送達率高不高。送達率這個概念,一直是個很混亂的概念,有些平臺會宣稱送達率能達到98%以上,而又有一些人說行業平均水平也就60%左右。
為什麼說法如此迥異呢?是因為大家在說的其實不是一個送達率。
友盟的訊息推送業務線負責人陳漠沙曾專門寫過一篇文章,來澄清送達率概念的一些誤解,文章寫得相當好,建議做推送業務的同學一定要讀一下:
關鍵是要分清此文中定義的“線上送達率”和“通用送達率”。
“線上送達率”,各個推送平臺優化到最後,可能都差不多。估計都能達到98%以上。
而“通用送達率”才是真真正正把訊息推送到你的App的最終的送達率,這個也才是使用者最終能感受到的送達率。App開發者需要真正關注的也是這個。
“通用送達率”大概來講,是最終到達App的訊息數與開始發出的訊息數的比率(在一定時間內監測)。跟這個比率直接有關的因素是兩個:
- 業務型別。比如你的App是個IM,那麼可能通用送達率會比較高,因為IM來的訊息比較重要,且需要接收的人儘快去閱讀處理。而如果你的App只是來推送一些系統訊息,那麼很多人可能壓根不會開啟你的App去看,這樣通用送達率自然就低。
- 推送的呼叫方式。這個和開發有關。比如,你的推送邏輯總給已經解除安裝了App的使用者傳送訊息,那麼對方肯定收不到了,造成通用送達率比較低。這種情況在群發的時候尤其顯著。
所以,這麼說起來,不同的App由於業務不同,推送呼叫方式也不同,那麼他們的通用送達率就沒有實質的可比性。
那假如我們推送做了某個優化,或者某天換了一個更好的第三方推送平臺,我們怎麼知道這個改動是好還是壞呢?答案是我們可以自己跟自己比。持續監測通用送達率,比較改動前後的變化。
擁抱變化
GitHub上有一個討論Android推送的帖子(由@Trinea建立):
這個帖子從2015年5月份開始討論至今,仍然沒有人給出一個完美的解決方案。
隨著各個手機廠商的市場份額的變化,以及推送平臺市場的變化,Android推送也是一個不斷處於變化中的話題。今天的結論,換到明天,也許就未必再適用。
所以,推送服務的實現者們也當然要擁抱變化。一定要確保你的推送架構能夠很容易地切換某個第三方的推送渠道。
多年的創業經驗告訴我們,不只是推送服務,也包括眾多其它的雲服務,僅僅依賴一家平臺的做法,都是極其愚蠢的。
由於國內的各大手機廠商對於安卓系統做了各種不同的定製,增加了很多安全性的限制,導致推送成了一個很複雜的問題。而這個市場中又沒有哪一家完美解決了所有手機裝置的推送送達的問題。同時,微信由於其先發優勢和規模優勢,進入了各大廠商受保護的白名單,進一步拉開了與其他App在推送送達率上的距離。
最後不由得感慨一句,如果谷歌一直在中國,還會有這種亂局出現嗎?
(完)
其它精選文章: