使用智慧型手機的期間,行動數據方案費用很容易超出裝置本身的成本。在 Android 7.0 (API 級別 24) 以上版本中,使用者可以啟用裝置中的數據節省模式,藉此達到最佳化,並減少數據用量。這種模式對帳單週期結束時的漫遊用量,或是小型預付數據方案特別有效。
使用者在「設定」中啟用數據節省模式,且使用計量付費網路時,系統會阻斷背景數據使用和訊號,並盡可能減少應用程式在前景使用的數據量。即使啟用數據節省模式,使用者依舊能允許特定應用程式的背景計量數據用量。
Android 7.0 (API 級別 24) 透過擷取數據節省模式的使用者偏好設定,並監控偏好設定的變更,擴充了ConnectivityManager
API 來提供應用程式。讓應用程式查看是否啟用數據節省模式,並盡力限制前景和背景數據的用量,這是相當不錯的做法。
查看數據節省模式偏好設定
在 Android 7.0 (API 級別 24) 以上版本中,應用程式可以使用 ConnectivityManager
API,決定要執行的數據用量限制。使用 getRestrictBackgroundStatus()
方法時,下列其中一個值會傳回:
-
RESTRICT_BACKGROUND_STATUS_DISABLED
- 數據節省模式已停用。
-
RESTRICT_BACKGROUND_STATUS_ENABLED
- 使用者已啟用數據節省模式,並限制該應用程式的數據用量。應用程式應盡量減少前景數據用量,並妥善處理背景數據用量的限制。
-
RESTRICT_BACKGROUND_STATUS_WHITELISTED
- 使用者已啟用數據節省模式,該應用程式不受此限。但仍須盡量限制前景和背景的數據用量。
即使停用數據節省模式或應用程式不受此限,裝置使用計量付費網路時,須限制數據用量。以下為程式碼範例,說明如何使用 ConnectivityManager.isActiveNetworkMetered()
和 ConnectivityManager.getRestrictBackgroundStatus()
來判斷應用程式應使用多少數據:
Kotlin
(getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).apply { // Checks if the device is on a metered network if (isActiveNetworkMetered) { // Checks user’s Data Saver settings. when (restrictBackgroundStatus) { RESTRICT_BACKGROUND_STATUS_ENABLED -> { // Background data usage is blocked for this app. Wherever possible, // the app should also use less data in the foreground. } RESTRICT_BACKGROUND_STATUS_WHITELISTED -> { // The app is allowed to bypass Data Saver. Nevertheless, wherever possible, // the app should use less data in the foreground and background. } RESTRICT_BACKGROUND_STATUS_DISABLED -> { // Data Saver is disabled. Since the device is connected to a // metered network, the app should use less data wherever possible. } } } else { // The device is not on a metered network. // Use data as required to perform syncs, downloads, and updates. } }
Java
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); // Checks if the device is on a metered network if (connMgr.isActiveNetworkMetered()) { // Checks user’s Data Saver settings. switch (connMgr.getRestrictBackgroundStatus()) { case RESTRICT_BACKGROUND_STATUS_ENABLED: // Background data usage is blocked for this app. Wherever possible, // the app should also use less data in the foreground. case RESTRICT_BACKGROUND_STATUS_WHITELISTED: // The app is allowed to bypass Data Saver. Nevertheless, wherever possible, // the app should use less data in the foreground and background. case RESTRICT_BACKGROUND_STATUS_DISABLED: // Data Saver is disabled. Since the device is connected to a // metered network, the app should use less data wherever possible. } } else { // The device is not on a metered network. // Use data as required to perform syncs, downloads, and updates. }
注意:Android TV 運作方式有所不同。Android TV 並不會禁止背景使用數據,而是會限制用量。前景應用程式用量限制為 800 Kbps,背景應用程式限制為 10 Kbps。如要偵測何時應限制電視數據用量,可使用 ConnectivityManager.isActiveNetworkMetered()
。
要求數據限制權限
如果應用程式需要在背景使用數據,可以傳送 Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS
意圖,內容包含該應用程式套件名稱的 URI,藉此要求數據限制權限,例如:package:MY_APP_ID
。
傳送意圖和 URI 會啟動「設定」應用程式,並顯示應用程式的數據用量設定。使用者依此決定是否授權,讓應用程式使用背景數據。較為妥當的做法是在傳送意圖前,先詢問使用者是否要啟動「設定」。
監控數據節省模式的偏好設定變更
應用程式透過建立 BroadcastReceiver
來監聽 ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED
,並使用 Context.registerReceiver()
進行接收器的動態記錄,從而監控數據節省模式的變更。收到這個廣播時,應用程式就會呼叫 ConnectivityManager.getRestrictBackgroundStatus()
來檢查新的數據節省模式偏好設定是否會影響其權限。
注意:廣播只會傳送給 Context.registerReceiver()
動態記錄的應用程式。數據使用不受影響的應用程式不會收到這個廣播。
使用 Android Debug Bridge 指令進行測試
在數據節省模式條件下,Android Debug Bridge (ADB) 提供幾個測試應用程式的指令。您可以檢查並設定網路權限,或將無線網路設為計量付費,如此便能在非計量付費的環境中測試應用程式。
-
$ adb shell dumpsys netpolicy
- 會產生報表,內容包括目前全球背景網路限制設定、目前不受數據節省模式影響的套件 UID,以及其他已知套件的網路權限。
-
$ adb shell cmd netpolicy
- 會顯示 Network Policy Manager (netpolicy) 完整的指令清單。
-
$ adb shell cmd netpolicy set restrict-background <boolean>
- 在分別傳遞
true
或false
時,啟用或停用數據節省模式。 -
$ adb shell cmd netpolicy add restrict-background-whitelist <UID>
- 將指定套件 UID 加入許可清單 (
whitelist
),允許使用其背景計量付費數據。 -
$ adb shell cmd netpolicy remove restrict-background-whitelist <UID>
- 將指定套件 UID 從許可清單 (
whitelist
) 中移除,從而在啟用數據節省模式時,封鎖其背景計量付費數據的使用。 -
$ adb shell cmd netpolicy list wifi-networks
- 列出所有 Wi-Fi,顯示是否為計量付費網路。
-
$ adb shell cmd netpolicy set metered-network <WIFI_SSID> true
- 將指定 SSID 的 Wi-Fi 網路設為計量付費,這樣即可用非計量付費的網路,模擬使用計量付費網路的情境。