沒推送功能,你好意思叫 app 嘛?
相信大家對(duì)推送這項(xiàng)技術(shù)并不陌生。如果沒聽說(shuō)過,那么作為一個(gè)充滿好奇心的孩子,你一定想過這個(gè)問題:睡覺前我明明關(guān)閉了淘寶、網(wǎng)易新聞等App為什么第二天他們又自動(dòng)出現(xiàn)在我手機(jī)的通知欄上呢?
這其實(shí)就是推送系統(tǒng)干的好事:在你睡覺的時(shí)候,服務(wù)器悄悄的向你的手機(jī)推送了一個(gè)消息,然后喚醒了你已經(jīng)關(guān)閉的App事實(shí)上,無(wú)論你愿意與否,現(xiàn)在大多數(shù)‘有節(jié)操’的App都已經(jīng)內(nèi)置了推送系統(tǒng),并時(shí)刻準(zhǔn)備著登上你的通知欄的‘頭條’。
傳統(tǒng)的App架構(gòu)里,通常是App主動(dòng)向服務(wù)器請(qǐng)求數(shù)據(jù),服務(wù)器被動(dòng)的提供數(shù)據(jù)。
以新聞客戶端App為例:App被用戶打開的時(shí)候,會(huì)通過網(wǎng)絡(luò)(無(wú)論3G、4G還是wifi)連接到服務(wù)器上,向服務(wù)器請(qǐng)求最新的新聞。服務(wù)器收到請(qǐng)求,從自己的數(shù)據(jù)庫(kù)里查詢最新的新聞,返回給AppApp收到服務(wù)器返回的數(shù)據(jù),經(jīng)過一系列的解析處理操作,最終把最新的新聞呈現(xiàn)給用戶,一次通信就完成了。然而如果此時(shí)服務(wù)器上又有了新的新聞,無(wú)論多么重要,在用戶沒有主動(dòng)刷新的情況下,是沒有辦法讓用戶看到的。推送就是為了解決這樣的困境的,它給了服務(wù)器一個(gè)展示自我的機(jī)會(huì),主動(dòng)連接上所有的App告訴他們我有新的新聞了,你們?cè)賮?lái)請(qǐng)求一次吧,于是收到推送的App即時(shí)此時(shí)已經(jīng)被用戶關(guān)閉了)又去服務(wù)器請(qǐng)求最新的新聞,這樣用戶就能看到最新的新聞了。
從技術(shù)上來(lái)講,實(shí)現(xiàn)一個(gè)推送系統(tǒng)需要服務(wù)器端和終端的配合。一種方法是輪詢,也就是不停的向服務(wù)器發(fā)起請(qǐng)求。這其實(shí)很好理解,作為App我既然不知道什么時(shí)候會(huì)發(fā)生新的新聞,那我一遍一遍的問好了,而且我知道這樣一定會(huì)成功的。顯而易見,這種方法App端費(fèi)時(shí)費(fèi)力不說(shuō),電量流量也扛不住啊,服務(wù)器要處理如此量大的請(qǐng)求,必然也是非常頭疼的。另一種方法是服務(wù)器和App建立一個(gè)長(zhǎng)時(shí)間連接的通道,通過這個(gè)通道,不僅App可以向服務(wù)器請(qǐng)求數(shù)據(jù),服務(wù)器也可以向App發(fā)送數(shù)據(jù),看起來(lái)非常完美;但是如果App被用戶關(guān)閉的話,通道就斷掉了。好在android系統(tǒng)給App提供了一個(gè)這樣的環(huán)境,App可以啟動(dòng)一個(gè)后臺(tái)服務(wù)來(lái)維持這個(gè)通道,即使App被關(guān)掉了,服務(wù)依然可以運(yùn)行,通道依然還在工作(ios后面會(huì)講)。
回到前面的例子,你在睡覺前關(guān)掉了淘寶,但是并沒有關(guān)閉淘寶的后臺(tái)服務(wù),淘寶依然可以接收服務(wù)器推送來(lái)的指令,把自己的喚醒。那么如何維持這樣的一條長(zhǎng)時(shí)間連接的通道呢?就好比兩個(gè)人打電話,一開始聊的熱情有來(lái)有往,后來(lái)慢慢沉默下來(lái)了,幾分鐘之后,電話的另一頭沒有任何動(dòng)靜,如何知道那邊的人還在呢?很簡(jiǎn)單,只需要另一頭的人每隔幾分鐘說(shuō)一個(gè)字就行。
同樣的道理,App會(huì)每隔一段時(shí)間向服務(wù)器報(bào)告自己還活著,就像心跳一樣,服務(wù)器收到后,就知道這個(gè)通道是可以繼續(xù)使用的了。然而天下沒有免費(fèi)的午餐,發(fā)送心跳是有代價(jià)的。一般手機(jī)鎖屏之后,為了省電CPU是出于休眠狀態(tài)的,然而發(fā)送心跳就會(huì)喚醒CPU,必然會(huì)增加電量的消耗。這還只是一個(gè)長(zhǎng)連接通道的情況,如果手機(jī)里裝了2、30個(gè)帶有推送的App呢?
先別急著抱怨,聰明的android工程師和ios工程師早就想到了這一點(diǎn),他們分別設(shè)計(jì)了GCM和APNS來(lái)解決多個(gè)App有多個(gè)長(zhǎng)連接通道的問題。
以APNS為例,ios開通了一條系統(tǒng)級(jí)別的長(zhǎng)連接通道,通道的一端是手機(jī)的所有App另一端是蘋果的服務(wù)器。App的服務(wù)器如果有新的消息需要推送的話,先把消息發(fā)送到蘋果的服務(wù)器上,再利用蘋果的服務(wù)器通過長(zhǎng)連接通道發(fā)送到用戶手機(jī),然后通知具體的App這樣就做到了即使手機(jī)安裝了100個(gè)App也只需要向一條通道里發(fā)送心跳。
回到Android,系統(tǒng)提供的GCM只能在Android2.2以上才能使用,3.0以下必須要安裝GooglePlay并登陸了Google賬號(hào)才能支持。而國(guó)內(nèi)發(fā)行的手機(jī)大多是閹割掉了google服務(wù)的。因此,對(duì)于Android系統(tǒng)來(lái)說(shuō),各家App只能各顯神通,開發(fā)自己的專用長(zhǎng)連接通道了。
然而這時(shí)候他們遇到了App的天敵:管家和衛(wèi)士們。前文說(shuō)了,App想要及時(shí)收到服務(wù)器推送的消息,關(guān)鍵在于自己與服務(wù)器的長(zhǎng)連接通道不被關(guān)閉,也就是自己的后臺(tái)服務(wù)可以一直在后臺(tái)運(yùn)行,而管家和衛(wèi)士們的一鍵清理功能就是專治這種“毒瘤”的。道高一尺魔高一丈,App在與管家和斗士們的長(zhǎng)期斗爭(zhēng)中,總結(jié)了一系列躲避被清理掉的方法;什么定時(shí)自啟能力、什么相互喚醒、什么前臺(tái)進(jìn)程等等。當(dāng)然這就是另一個(gè)話題了,我們后面會(huì)講到。
總結(jié)起來(lái),App和后臺(tái)的連接方式有兩種。一種叫Pull,也叫輪詢,就是定期的不斷向后臺(tái)請(qǐng)求;缺點(diǎn)是耗電,費(fèi)流量,不環(huán)保。對(duì)于一名有追求的程序員,他應(yīng)該會(huì)比較惡心這種方式的,你千萬(wàn)不要對(duì)他說(shuō),我不管你怎么實(shí)現(xiàn),我就要這種效果這種笨蛋話了,凡事應(yīng)該找到最優(yōu)路徑。另一種叫Push,App和后臺(tái)一直維持了一條通信通道,兩端不定期的就會(huì)偷摸的約會(huì),告訴對(duì)方“I’mHere”,也能順帶把信息互相攜帶了。缺點(diǎn)是要維持一條長(zhǎng)連接通道,這條通道容易被其他程序殺死,要多想復(fù)活辦法。
作者@微信公眾號(hào)“給產(chǎn)品經(jīng)理講技術(shù)”(pm_teacher)??文章來(lái)源@36氪
原文地址:http://36kr.com/p/5041230.html
不錯(cuò),淺顯易懂
ceshihyongli
學(xué)習(xí)了~
簡(jiǎn)明易懂,謝謝作者