而對於客戶端須要解決的以下幾個問題:服務器
1. 如何維護客戶端id與路由之間的綁定關係;網絡
2. 如何延長客戶端的在線狀態(app保活) app
3. 客戶端性能考慮socket
下面將針對這幾點進行逐步介紹tcp
維護客戶端與路由的綁定關係工具
這裏咱們須要瞭解一下NAT,所謂NAT就是,在局域網內部網絡中使用內部地址,而當內部節點要與外部網絡進行通信時,就在網關處,將內部地址替換成公用地址,從而在外部公網上正常使用。性能
因此當發送udp包到服務器時,服務器拿到的ip和端口實際上是客戶端在路由上映射的ip和端口,因此咱們須要維護路由上的映射表,這時就須要按期發送心跳包,以保證路由上的映射關係不會被清除掉。測試
1. 維護心跳包優化
主要做用是防止NAT超時, 和探測鏈接是否斷開,並根據實際狀況進行重連操做,其流程以下:ui
2. 網絡監測
當網絡切換和變化時,會致使映射關係失效,因此咱們須要作相應的監測和重連
1. 監聽網絡變化,當網絡類型變化或者斷開後從新鏈接上時,進行重連
2. 按期監測ip地址變化,若是監測到ip地址有變化時,則進行重連
APP保活
app保活是一個老生常談的話題,通過廣大開發者多年累積與篩選,互聯網上相關文章層出不窮,目前看來不算什麼硬梗,大多都按套路出行,這裏也套路套路
當應用退到後臺時,爲了確保推送通道可以正常使用而不被系統回收,一般會作一些進程保活和拉活的策略,大致分爲如下幾類:
1. 利用系統Service機制拉活
將 Service 設置爲 START_STICKY,利用系統機制在 Service 掛掉後自動拉活
以下兩種狀況沒法拉活:
1.Service 第一次被異常殺死後會在5秒內重啓,第二次被殺死會在10秒內重啓,第三次會在20秒內重啓,一旦在短期內 Service 被殺死達到5次,則系統再也不拉起。
2.進程被取得 Root 權限的管理工具或系統工具經過 forestop 中止掉,沒法重啓。
經測試,在絕大多數手機任務進程中,手動殺掉進程後,是不會自動重啓的(符合狀況2)
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如下版本纔有效,以下:
if (Build.VERSION.SDK_INT < 18) {
service.startForeground(1001, new Notification());//API < 18 ,此方法能有效隱藏Notification上的圖標
}
```
```
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_PRESENT);
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
```
4. 使用AlarmManager
使用AlarmManager定時發送心跳、定時檢查ip變化
可是經測試當系統休眠時,AlarmManager也中止了工做,且在不一樣sdk版本上須要採用不一樣的set方式,以下:
```
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
if (pingPendingIntent != null) {
am.cancel(pingPendingIntent);
}
pingPendingIntent = PendingIntent.getBroadcast(MobSDK.getContext(), 0, new Intent(ALARM_ACTION_PING),
PendingIntent.FLAG_UPDATE_CURRENT);
final long nextTime = SystemClock.elapsedRealtime() + interval * 1000L;
if (Build.VERSION.SDK_INT >= 23) {
am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, pingPendingIntent);
} else if (Build.VERSION.SDK_INT >= 19) {
am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, pingPendingIntent);
} else {
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, pingPendingIntent);
}
```
5. 進程間相互拉活
當某臺手機上有多個應用都在使用sdk時,可根據用戶在後臺配置受權後,選擇性的進行相互之間的拉活
6. 利用native進程拉活
網絡中流傳的一種利用 Linux 中的 fork 機制建立 Native 進程,在 Native 進程中監控主進程的存活,當主進程掛掉後,在 Native 進程中當即對主進程進行拉活。
在 Android 中全部進程和系統組件的生命週期受 ActivityManagerService 的統一管理。並且,經過 Linux 的 fork 機制建立的進程爲純 Linux 進程,其生命週期不受 Android 的管理。
這種方案在網上流傳已久,據說在5.0以上版本也不成立,且須要額外添加本地代碼編譯so,無形的添加了app體積,不採納
7. JobScheduler和帳號同步機制拉活
這種兩種方式一樣須要在AndroidManifest.xml中註冊相關配置和權限,版本限制,效果通常
8. 將應用加入廠商或管理軟件白名單
9. 第三方push通道接入:
GSM:國內不支持
小米推送、華爲推送
性能考慮
APP性能也是老生常談的話題,總結其出發點和最終的目的都是爲了減小用戶流量、內存佔用、電量消耗等等方面的優化,以達到省電省流量且界面流暢的終極目標。
在開發時,大體可從以下幾個方面思考和稍加註意:
1. 減小網絡請求次數,縮小網絡中傳輸數據的體積,像推送這種主動的操做,可經過自定義數據傳輸協議來控制流量的消耗
2. 控制喚醒屏幕,避免開啓不必的線程,合理釋放資源,減小IO操做,避免使用廣播機制,減小cup佔用時間等等方面來控制內存和電量的消耗