在智能手机的整个生命周期内,移动数据网络流量套餐的费用往往会超出手机的身价。在 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()
检测 Android TV 在何时限制流量消耗。
请求流量限制权限
如果您的应用需要在后台消耗流量,它可以发送 Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS
intent 来请求流量限制权限,该 intent 包含您的应用软件包名称的 URI,例如 package:MY_APP_ID
。
发送该 intent 和 URI 时,会启动设置应用,并显示应用的流量消耗设置。用户随后可以决定是否允许您的应用在后台使用流量。在发送此 intent 之前,最好先询问用户是否要为了启用后台流量消耗而启动设置应用。
监控流量节省程序偏好设置的变更
应用可以监控流量节省程序偏好设置的变更,方法是创建一个用于监听 ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED
的 BroadcastReceiver
,并向 Context.registerReceiver()
动态注册该接收器。应用收到此广播后,应调用 ConnectivityManager.getRestrictBackgroundStatus()
来检查新的流量节省程序偏好设置是否会影响其权限。
注意:系统只会将此广播发送给向 Context.registerReceiver()
动态注册以接收此广播的应用。在清单中注册以接收此广播的应用将不会收到此广播。
使用 Android 调试桥命令进行测试
Android 调试桥 (ADB) 提供了一些命令,可用于在流量节省程序条件下测试您的应用。您可以检查和配置网络权限,或者将无线网络设为按流量计费,以便在不按流量计费的网络上测试您的应用。
-
$ adb shell dumpsys netpolicy
- 生成一个报告,其中包括当前全局后台网络限制设置、当前被允许绕过流量节省程序的软件包 UID 以及其他已知软件包的网络权限。
-
$ adb shell cmd netpolicy
- 显示网络政策管理中心 (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 设为按流量计费,以便在不按流量计费的网络上模拟按流量计费的网络。