问题
I need to detect the local IP address and subnet mask on the WiFi network, on an Android device (in order to proper calculate the UDP broadcast address strictly for the local subnet).
When the device is connected to an Access Point, the following is properly working:
// 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);
But it doesn't work when it's the android device providing an Access Point though tethering: DhcpInfo seem to contain info set by the DCHP server when the Android device is a client of it, not when it's the Android device itself providing the DHCP service. When in tethering, the most promising solution I could find is:
// 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*/ );
EDIT: WRONG, in my tests even this only works when NOT tethering. While tethering the IP is always 0.
But there's nothing like WifiInfo.getNetMask()
, how can I get the subnet mask in that case? (This absence strikes me as really strange, since there's a plethora of other info there. Am I missing something obvious?)
Also, ideally I'd like a solution that doesn't need to discriminate if the Android device is providing tethering, and just get the local IP address and subnet mask, on the WiFi network, in any case, both when the Android device is providing or a client of an Access Point.
Even standard Java (i.e. not Android-specific) NetworkInterface.getNetworkInterfaces()
, don't seem to have a way to get the subnet mask (apart from not allowing to discriminate which corresponds to the WiFi). What am I missing?
回答1:
Best solution I found at the moment:
It baffles me how info/interface about tethering is so cumbersome/hidden to get, and yet not taken into consideration when you get info from WifiManager
, or ConnectivityManager
for the Wifi type: it all works only when NOT in tethering. I'm actually lost to that branch of investigation.
Best solution I found at the moment is using standard Java NetworkInterface.getNetworkInterfaces()
, instead of any Android API.
Experimentally, Android seems smart enough to set to null broadcast for network interfaces to the external mobile network. It actually makes lot of sense since Android silently drop UDP broadcasts involving external mobile network.
// 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
}
}
As for subnet mask, the result from getNetworkPrefixLength()
can be coerced into a subnet mask. I used getBroadcast()
directly since that was my ultimate goal.
No special permissions seem to be needed for this code (no ACCESS_WIFI_STATE
nor NETWORK
, just INTERNET
).
Primary reference for the code snippet: http://enigma2eureka.blogspot.it/2009/08/finding-your-ip-v4-broadcast-address.html
来源:https://stackoverflow.com/questions/28283915/android-detect-local-ip-and-subnet-mask-for-wifi-both-while-tethering-and-conn