优化网络流量消耗

在智能手机的整个生命周期中,移动数据网络计划的成本通常会超出设备本身的成本。从 Android 7.0(API 级别 24)开始,用户可以在整个设备上启用流量节省程序,以优化其设备的流量消耗,减少数据使用。无论是在漫游、账单周期即将结束,还是使用少量的预付费数据包时,此功能都特别有用。

当用户在 Settings 中启用流量节省程序且设备已接入按流量计费的网络中时,系统会屏蔽后台流量消耗,同时指示应用在前台尽可能使用较少的数据。用户可以将特定应用加入白名单以允许其在后台使用计费流量,即使在流量节省程序开启时也是如此。

Anndroid 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 whitelisted. 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 whitelisted. 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.
}

请求白名单权限

如果您的应用需要使用后台数据,它可以通过发送一项包含您的应用软件包名称 URI 的 Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS Intent 来请求白名单权限:例如 package:MY_APP_ID

发送 Intent 和 URI 将启动 Settings 应用,并会显示您应用的流量消耗设置。随后,用户可以决定是否启用应用的后台数据。在您发送此 Intent 之前,请先询问用户是否希望启用 Settings 应用,以启用后台流量消耗,这是一种有效的做法。

监控流量节省程序偏好变化

应用可以通过创建 BroadcastReceiver 侦听 ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED,以及使用 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>
在分别传递 truefalse 时,启用或停用流量节省程序模式。
$ adb shell cmd netpolicy add restrict-background-whitelist <UID>
将指定软件包 UID 加入白名单,以允许后台按流量计费的流量消耗。
$ adb shell cmd netpolicy remove restrict-background-whitelist <UID>
从白名单中移除指定软件包 UID,以阻止当流量节省程序启用时后台按流量计费的流量消耗。
$ adb shell cmd netpolicy list wifi-networks
列出所有 WiFi 网络,显示它们是否按流量计费。
$ adb shell cmd netpolicy set metered-network <WIFI_SSID> true
使用指定的 SSID 将 WiFi 设置为按流量计费,以便您在无限流量网络上模拟按流量计费的网络。