而對於客戶端需要解決的如下幾個問題:
1. 如何維護客戶端id與路由之間的繫結關係;
2. 如何延長客戶端的線上狀態(app保活)
3. 客戶端效能考慮
下面將針對這幾點進行逐步介紹
維護客戶端與路由的繫結關係
這裡我們需要了解一下NAT,所謂NAT就是,在區域網內部網路中使用內部地址,而當內部節點要與外部網路進行通訊時,就在閘道器處,將內部地址替換成公用地址,從而在外部公網上正常使用。
所以當傳送udp包到伺服器時,伺服器拿到的ip和埠其實是客戶端在路由上對映的ip和埠,所以我們需要維護路由上的對映表,這時就需要定期傳送心跳包,以保證路由上的對映關係不會被清除掉。
1. 維護心跳包
主要作用是防止NAT超時, 和探測連線是否斷開,並根據實際情況進行重連操作,其流程如下:
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佔用時間等等方面來控制記憶體和電量的消耗