在智能手机的使用寿命内,蜂窝数据流量套餐的费用很容易超过设备本身的费用。在 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()
来检测何时在 TV 上限制数据使用。
请求数据限制权限
如果您的应用需要在后台使用数据,可以通过发送包含应用软件包名称 URI(例如,package:MY_APP_ID
)的 Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS
intent 来请求数据限制权限。
发送此 intent 和 URI 会启动设置应用,并显示应用的流量使用量设置。然后,用户可以决定是否为此应用启用后台数据。在发送此 intent 之前,建议先询问用户是否要启动设置应用来启用后台数据使用。
监控流量节省程序偏好设置的变化
应用可以通过创建 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>
- 从允许列表(
whitelist
)中移除指定的软件包 UID,以在流量节省程序启用时阻止按流量计费的后台数据使用。 -
$ adb shell cmd netpolicy list wifi-networks
- 列出所有 Wi-Fi 网络,并显示其是否按流量计费。
-
$ adb shell cmd netpolicy set metered-network <WIFI_SSID> true
- 将具有指定 SSID 的 Wi-Fi 设置为按流量计费,以便在非按流量计费的网络上模拟按流量计费的网络。