最近在做一个Android关于的无线局域网项目,需要获取本机在所连接局域网上的IP地址。手机可以通过WIFI连接已知的局域网,也可通过打开手机热点去组建一个局域网。
在通过WIFI连接局域网时,本机的 IP 地址可以通过 “ WifiManager ” 和“ WifiInfo ”获得,如下:
public static String getIP(Context context) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (wifiManager.isWifiEnabled()) {
// 若已经开启了 WIFI
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ip = wifiInfo.getIpAddress();
return (ip & 0xFF) + "." + ((ip >> 8) & 0xFF) + "." + ((ip >> 16) & 0xFF) + "." + ((ip >> 24) & 0xFF);
} else {
// 未打开 WIFI
return null;
}
}
但是如果通过“便携式热点”的方式自己开启局域网时,本机的 IP 一时想不到方案怎么获取(上述方式就不管用了,因为手机开启热点后WIFI会被关闭)。终于通过这篇文章有了可行的解决办法:
Android 中获取本机热点ip地址_android 获取usb共享网络设备的ip-CSDN博客
大致的原理是通过遍历所有已知的网络接口,最后找到名为“ wlan0 ”(或“eth0”或“ap0”)的无线局域网接口即可。我通过下面代码大致输出了一下它的遍历结果(因为我的Android Studio不知道为什么在打 log 输出时,IP地址会显示为 “********”,因此我把‘.’ 替换成了 ‘@’,有知道的小伙伴告诉我一下,谢谢!):
public static InetAddress getApIpAddress2() {
try {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
Log.d("test", "networkInterface: " + networkInterface.getDisplayName());
// getInetAddresses
Enumeration<InetAddress> ipAddresses = networkInterface.getInetAddresses();
while (ipAddresses.hasMoreElements()) {
InetAddress inetAddress = ipAddresses.nextElement();
Log.d("test", " inetAddress: " + inetAddress.toString().replace('.','@'));
}
// getInterfaceAddresses
List<InterfaceAddress> interfaceAddressList = networkInterface.getInterfaceAddresses();
for (InterfaceAddress interfaceAddress : interfaceAddressList) {
Log.d("test", " interfaceAddress: " + interfaceAddress.getAddress().toString().replace('.','@') + " " + interfaceAddress.getNetworkPrefixLength());
}
}
} catch (SocketException e) {
e.printStackTrace();
}
return null;
}
上面的代码得到的结果是(此时我手机连上了另一台手机的热点):
可以看到,在名为“ wlan0 ”(或“eth0”或“ap0”)的网络接口中,找到了我所需要的 IP 地址甚至是网络前缀。但是同时也存在了一个 Ipv6 的输出(链路本地地址 LinkLocalAddress),这个我不需要,等一下在正式代码中我可以将其过滤掉。因此,结论: 找到DisplayName 为 “wlan0”(或“eth0”或“ap0”)的网络接口,再对 “wlan0”(或“eth0”或“ap0”)内的地址做过滤即可。
下面是正式代码:
public static String getApIpAddress2() {
try {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
if (networkInterface.getDisplayName().contains("wlan0") ||
networkInterface.getDisplayName().contains("eth0") ||
networkInterface.getDisplayName().contains("ap0")) {
// getInterfaceAddresses
List<InterfaceAddress> interfaceAddressList = networkInterface.getInterfaceAddresses();
for (InterfaceAddress interfaceAddress : interfaceAddressList) {
InetAddress inetAddress = interfaceAddress.getAddress();
if (!inetAddress.isLinkLocalAddress()) { // 过滤掉 链路本地地址
// 获取网络前缀(子网掩码)
int prefix = interfaceAddress.getNetworkPrefixLength();
// 输出:192.168.43.197/24
return inetAddress.toString().substring(1) + "/" + prefix;
}
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
return null;
}
说明:
正式代码经过测试,可以获取到连接 WIFI 时本机的 IP 地址,也可以获取到作为热点源时 本机的 IP 地址。
代码中,返回时为什么要subString(1)呢?是因为InetAddress.toString()时会加上“/”,比如“/192.168.43.197”,因此需要将这个斜杠去掉。
什么原因结果会返回 null 呢?返回 null 是因为找不到 “wlan0”(或“eth0”或“ap0”),找不到“wlan0”(或“eth0”或“ap0”)大概率是因为没有打开 WIFI 或 热点。
上述代码只是从我观察到的现象来写出的,可靠性仍不清楚,比如对于不同手机中 “wlan0”的名字是否唯一、是否都叫这个名等等的不确定性,仍然需要结合实际去使用。本文只是记录一下这个方法而已😂。
若有其他的更好更可靠的方式的话,欢迎交流指导,同时本文若有错误,敬请各位指出,作为新人表示十分感谢!
————————————————
版权声明:本文为CSDN博主「养马的农民」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45204138/article/details/133946381