推送定義:在任何時間地點服務端向用戶端推送一條消息,如果用戶端線上或者下次上線,就能接收到該消息。
通常想到的實作方式是:輪詢、tcp長連,其目的都是讓服務端和用戶端之間時刻保持線上狀态
對于用戶端而言,
輪詢:無非是寫個線程按某種配置的時間間隔無限循環去請求服務端是否有新的消息,當有新的消息,就提醒給使用者
tcp長連:與服務端建立tcp長連,這樣服務端就可以直接給用戶端發送消息了,目前市面上基本上是以此種方式居多
udp無連接配接:其實作基本原理為,用戶端建立socket并向服務端發送udp包,服務端接收到請求連接配接的udp包之後,将用戶端id與ip和端口号進行綁定,當要向某個用戶端id發送消息時,找到其對應的ip和端口号,然後将消息組裝成udp包發送即可,其大緻流程如下:.

而對于用戶端需要解決的如下幾個問題:
如何維護用戶端id與路由之間的綁定關系;
如何延長用戶端的線上狀态(app保活)
用戶端性能考慮
下面将針對這幾點進行逐漸介紹
維護用戶端與路由的綁定關系
這裡我們需要了解一下NAT,所謂NAT就是,在區域網路内部網絡中使用内部位址,而當内部節點要與外部網絡進行通訊時,就在網關處,将内部位址替換成公用位址,進而在外部公網上正常使用。
是以當發送udp包到伺服器時,伺服器拿到的ip和端口其實是用戶端在路由上映射的ip和端口,是以我們需要維護路由上的映射表,這時就需要定期發送心跳包,以保證路由上的映射關系不會被清除掉。
維護心跳包
主要作用是防止NAT逾時, 和探測連接配接是否斷開,并根據實際情況進行重連操作,其流程如下:
網絡監測
當網絡切換和變化時,會導緻映射關系失效,是以我們需要做相應的監測和重連
監聽網絡變化,當網絡類型變化或者斷開後重新連接配接上時,進行重連
定期監測ip位址變化,如果監測到ip位址有變化時,則進行重連
APP保活
app保活是一個老生常談的話題,經過廣大開發者多年累積與篩選,網際網路上相關文章層出不窮,目前看來不算什麼硬梗,大多都按套路出行,這裡也套路套路
當應用退到背景時,為了確定推送通道能夠正常使用而不被系統回收,通常會做一些程序保活和拉活的政策,大體分為以下幾類:
利用系統Service機制拉活
将 Service 設定為 START_STICKY,利用系統機制在 Service 挂掉後自動拉活
如下兩種情況無法拉活:
1.Service 第一次被異常殺死後會在5秒内重新開機,第二次被殺死會在10秒内重新開機,第三次會在20秒内重新開機,一旦在短時間内 Service 被殺死達到5次,則系統不再拉起。
2.程序被取得 Root 權限的管理工具或系統工具通過 forestop 停止掉,無法重新開機。
經測試,在絕大多數手機任務程序中,手動殺掉程序後,是不會自動重新開機的(符合情況2)
設定程序優先級
當程序退到背景後,系統在回收資源時,會根據程序優先級,進行資源回收,優先級越高越晚被回收,是以盡可能地提高service程序的優先級,可以在一定程度上保障其在背景時不被系統回收
程序按照重要性分為如下5類:
1.前台程序(Foreground process)
2.可見程序(Visible process)
3.服務程序(Service process)
4.背景程序(Background process)
5.空程序(Empty process)
一般的背景程序程序屬于第4類,我們可以通過setForeground将service提升到2,但是這種方案必須與一條可見的通知綁定在一起,而這種體驗顯然不能被使用者接受
當然我們可以通過new Notification()的方式設定一個空的通知,與之綁定,但隻在4.3以下版本才有效,如下:
神奇的開發者們發現了一種通過多實作一個TmpService,在MainService和TmpService兩個service中同時發送具有相同 ID 的 Notification,然後幹掉TmpService,這時Notification會自動消失,而MainService的優先級已經被提升到2了,進而達到了目的。缺陷是:需要開發者在manifest多配置一個service,可能在不久的将來也會被官方更新掉,不建議采納。
利用系統廣播拉活
該方式是通過AndroidManifest.xml 注冊一些特定的系統廣播方式,來拉活程序,但是這種方式在高版本中已經被官方封掉了,是以也成了一堆沒必要的配置
當然我們可以在代碼中添加了相關的系統廣播注冊、同時在監聽程序死掉時發送的廣播,測試在某些低版本的手機上有效
使用AlarmManager
使用AlarmManager定時發送心跳、定時檢查ip變化
但是經測試當系統休眠時,AlarmManager也停止了工作,且在不同sdk版本上需要采用不同的set方式,如下: