Android - 为什么 ConnectivityManager.isActiveNetworkMetered 总是返回 true(即使在 Wifi 上)

标签 android wifi android-wifi

在我的 Android 音乐流应用程序中,下面的代码路径有助于根据 ConnectivityManager 类实例返回的值在高比特率流和低比特率之间做出决定。

我试图理解为什么 ConnectivityManager.isActiveNetworkMetered() 会返回“true”,当它很明显是在本地 Wifi 网络上时。采用以下 Android/Java 代码:

boolean isMetered = false;
boolean isWifi = false;
boolean isEthernet = false;
boolean isRoaming = false;
boolean isConnected = false;

NetworkInfo netinfo = connManager.getActiveNetworkInfo();
if (netinfo != null)
{
    isWifi = (netinfo.getType() == ConnectivityManager.TYPE_WIFI);
    isEthernet = (netinfo.getType() == ConnectivityManager.TYPE_ETHERNET);
    isRoaming = netinfo.isRoaming();
    isConnected = netinfo.isConnected();

    Log.d(TAG, "active network type = " + netinfo.getTypeName());
    Log.d(TAG, "active network subtype = " + netinfo.getSubtypeName());


    Log.d(TAG, "isConnected = " + isConnected);
    Log.d(TAG, "isWifi = " + isWifi);
    Log.d(TAG, "isEthernet = " + isEthernet);
    Log.d(TAG, "isRoaming = " + isRoaming);
}

// isActiveNetworkMetered was introduced in API 16 (Jelly Bean)
if (android.os.Build.VERSION.SDK_INT >= 16)
{
    isMetered = connManager.isActiveNetworkMetered();
    Log.d(TAG, "isMetered = " + isMetered);
}

当我关闭 Wifi 并且我唯一的连接是 AT&T 的 LTE 网络时,它会在日志控制台中打印出以下内容:

active network type = mobile
active network subtype = LTE
isConnected = true
isWifi = false
isEthernet = false
isRoaming = false
isMetered = true

以上一切都符合预期 - 我使用的是按流量计费的移动运营商网络。

现在切换到我家的 Wifi,同样的代码块会打印出这个:

active network type = WIFI
active network subtype = 
isConnected = true
isWifi = true
isEthernet = false
isRoaming = false
isMetered = true

为什么 isMetered,即 isActiveNetworkMetered 的结果,仍然显示为 true?这导致以下代码路径支持较低比特率流,即使我在我的家庭 wifi 网络上也是如此:

if ((isWifi || isEthernet) && !isMetered)
{
    result = BITRATE_HIGH_KBIT_SEC;
}
else
{
    result = BITRATE_LOW_KBIT_SEC;
}

isActiveNetworkMetered() 如何决定网络是否被计量?这是WIFI协商的一部分还是SSID广播中的一点? Android 上的网络设置?我在我的 Android Kitkat 设备上找不到任何设置来切换或发现按流量计费网络的设置。

上周我的 ISP (Frontier) 给我寄来了一个新的 Wifi 路由器。可能有关系?我在路由器的固件页面上没有看到任何此类设置。

我今天晚些时候会去上类,看看它在另一个网络上的表现如何。无论如何,我可能会编辑上面的代码以跳过计量检查,除非我能证明它只是某处的错误设置。

更新 - 始终返回按流量计费网络的问题在我的 HTC One M8 手机(运行 Kitkat)上重现,但在我的 2012 年 Nexus 7(也升级到 Android 4.4 Kitkat)上没有重现。

问题已解决 - 原来我的 Wifi 被我的手机标记为“移动热点”。关于如何查找和切换此标志的更多详细信息是 here .

最佳答案

我也对此进行了测试,但我观察到的是“预期”结果:WiFi 为 false,3G 为 true。这是在装有 Android 4.4.2 的 Nexus 4 中。

奇怪的是 ConnectivityManagerCompat class在支持库中 确实 为 WiFi 返回 false。

final int type = info.getType();
switch (type) {
    case TYPE_MOBILE:
        return true;
    case TYPE_WIFI:
        return false;
    default:
        // err on side of caution
        return true;
}

编辑 - 找到了(我认为)

NetworkPolicyManagerService 似乎是最终为该方法生成结果的类。根据它,WiFi 连接确实可以计量。它包含一个 BroadcastReceiver,“监听 wifi 状态变化以捕获计量提示”(第 567 行)。此信息是从 NetworkInfo.getMeteredHint() 获得的,仔细检查后,其中包含以下有趣的注释:

/**
 * Flag indicating that AP has hinted that upstream connection is metered,
 * and sensitive to heavy data transfers.
 */
private boolean mMeteredHint;

这个标志是从DhcpResults.hasMeteredHint()加载的

/**
 * Test if this DHCP lease includes vendor hint that network link is
 * metered, and sensitive to heavy data transfers.
 */
public boolean hasMeteredHint() {
    if (vendorInfo != null) {
        return vendorInfo.contains("ANDROID_METERED");
    } else {
        return false;
    }
}

所以看起来,AP 确实可以通知它的 WiFi 客户端底层互联网连接是通过使用这个标志来计量的。

EDIT #2 相关信息,来自http://www.lorier.net/docs/android-metered

When an android phone is using another android phone's hotspot, it knows it's on a "metered connection" and therefore disables the expensive sync options ( eg: photo sync). How does it know this? The android hotspot sends DHCP Option 43 (Vendor specific options) with the value ANDROID_METERED. The client, if it sees ANDROID_METERED anywhere in the option 43 values, turns on the "expensive data connection" option.

看起来添加此标志是为了与另一台 Android 设备提供的热点“玩得开心”。

编辑 #3 commit that introduced this feature :

Connect metered DHCP hint for Wi-Fi networks.

When DHCP lease includes vendor info indicating that remote Wi-Fi network is metered, advise NetworkPolicy. Users can still manually change the metered flag in Settings.

您可以通过以下方式访问此设置:

Settings -> Data Usage -> (Overflow Menu) -> Mobile Hotspots

关于Android - 为什么 ConnectivityManager.isActiveNetworkMetered 总是返回 true(即使在 Wifi 上),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23877476/

相关文章:

Android Systrace 跟踪文件格式

java - 如何将图标和自定义 TextView 添加到自定义 float 操作按钮

android - 如何在 onCreate 后立即启动动画?

java - Android WifiManager getScanResult 提示需要 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION 权限,尽管已声明权限

android - 如何在android中获取wifi配置文件位置

wifi - 扫描wifi结果重复SSID

安卓 Kotlin : Required Context but found String

Android 永久禁用/启用 Wifi 和蓝牙

c# - 无法通过 Wifi 从 Android 应用程序访问另一台机器中存在的图像文件夹

bluetooth - 为什么 Wi-Fi 的带宽比蓝牙大得多?