Android,检测WiFi的本地IP地址和子网掩码,在连接访问点和热点时都可用。

4

我需要在Android设备上检测WiFi网络中的本地IP地址和子网掩码,以便严格计算本地子网的UDP广播地址。

当设备连接到接入点时,以下内容正常工作:

// Only works when NOT tethering
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

DhcpInfo dhcp = wifi.getDhcpInfo();
if (dhcp == null)
    throw new IOException("No DHCPInfo on WiFi side.");

foo(dhcp.ipAddress, dhcp.netmask);

但是,当安卓设备通过热点共享提供访问点时,它似乎无法正常工作:DhcpInfo似乎包含的信息是由DHCP服务器设置的,当安卓设备作为其客户端时,而不是当安卓设备本身提供DHCP服务时。在热点共享时,我找到的最有前途的解决方案是:

// No way to get subnet mask
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

WifiInfo info = wifi.getConnectionInfo();
if (info == null)
   throw new IOException("No connection info on WiFi side.");

foo(info.getIpAddress(), info.??? /* netmask*/ );

编辑:错误,根据我的测试,即使是这种情况下,仅在没有使用网络共享时才有效。当使用网络共享时,IP地址始终为0。

但是并没有像WifiInfo.getNetMask()一样的方法,那么我该如何获取子网掩码呢?(这个缺失让我感到非常奇怪,因为还有其他大量信息可供使用。我是否错过了什么显而易见的东西?)

此外,理想情况下,我希望不需要区分Android设备是否提供网络共享,只需在任何情况下都可以获取WiFi网络上的本地IP地址和子网掩码,无论Android设备是提供者还是Access Point的客户端。

甚至标准Java(即非Android特定的)NetworkInterface.getNetworkInterfaces()似乎也没有办法获取子网掩码(除了不允许区分哪个对应于WiFi之外)。我错过了什么吗?


请将您的解决方案发布为自己问题的答案(http://stackoverflow.com/help/self-answer)。然后将其标记为已接受的答案。这将帮助其他用户更快地找到解决方案。如果以后有更好的解决方案,您可以随时更新答案或发布第二个答案并将其标记为有效答案。这将保留有关旧版本的信息。 - Marvin Emil Brach
1
完成。感谢提示。 - GozzoMan
1个回答

5

目前我找到的最佳解决方案:

我很困惑,关于网络共享的信息/界面如此繁琐/难以获取,但在从WifiManagerConnectivityManager获取Wifi类型的信息时却没有考虑到网络共享。只有在不使用网络共享时才能正常工作。我对这个调查分支感到迷茫。

目前我找到的最佳解决方案是使用标准Java NetworkInterface.getNetworkInterfaces(),而不是任何Android API。

实验表明,Android似乎足够智能,可以将外部移动网络的网络接口广播设置为null。这实际上是有道理的,因为Android会默默地丢弃涉及外部移动网络的UDP广播。

    // This works both in tethering and when connected to an Access Point

    Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();

    while (interfaces.hasMoreElements()) 
    {
        NetworkInterface networkInterface = interfaces.nextElement();

        if (networkInterface.isLoopback())
            continue; // Don't want to broadcast to the loopback interface

        for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) 
        {
                InetAddress broadcast = interfaceAddress.getBroadcast();

                // InetAddress ip = interfaceAddress.getAddress();                  
                // interfaceAddress.getNetworkPrefixLength() is another way to express subnet mask

                // Android seems smart enough to set to null broadcast to
                //  the external mobile network. It makes sense since Android
                //  silently drop UDP broadcasts involving external mobile network.
                if (broadcast == null)
                    continue;

                ... // Use the broadcast                
        }
    }

关于子网掩码,getNetworkPrefixLength() 的结果可以被强制转换为一个子网掩码。我直接使用了 getBroadcast(),因为那是我的最终目标。
对于此代码,似乎不需要特殊权限(没有 ACCESS_WIFI_STATENETWORK,只需 INTERNET)。
代码片段的主要参考来源:http://enigma2eureka.blogspot.it/2009/08/finding-your-ip-v4-broadcast-address.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接