Android 获取ip地址多种方式
文章目录
一、前言
adb shell 的 ifconfig可以获取当前设备网络节点信息;
这些信息使用Android代码也是可以获取的;
Android 获取网络ip有多种方式,有时候某种方式获取失败的情况下;
那么就可以换一种获取方式,所有多学习一下获取网络ip相关信息是有用的。
本文介绍三种获取网络ip信息的方式,并且最后一种的代码不用任何权限就能获取到相关节点的ip和MAC地址,有兴趣的可以看看。
二、获取ip地址
1、adb shell ifconfig
console:/ # ifconfig
wlan0 Link encap:Ethernet HWaddr 38:64:07:88:6a:f6 Driver usb
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3000
RX bytes:0 TX bytes:0
。。。
ap0 Link encap:Ethernet HWaddr 3e:ea:29:0a:07:d9
inet addr:192.168.43.1 Bcast:192.168.43.255 Mask:255.255.255.0
inet6 addr: fe80::3cea:29ff:fe0a:7d9/64 Scope: Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 TX bytes:1450
一般情况热点的节点名称都是ap0,可以看到ip地址和相关信息。
上面的wifi未连接所以才没有ip地址,如果有有线网ip也会显示。
一般情况下网络对应节点名称:
wifi节点:wlan0,
热点:ap0/wlan1,
有线网:eth0/eth1
投屏节点:p2p
2、Android 代码获连接的wifi 的 ip地址:
public static String getWifiIpAddress(Context context) {
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (!wifiManager.isWifiEnabled()) {
// Wi-Fi is not enabled, return null or handle the case accordingly
return null;
}
int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
byte[] bytes = new byte[4];
for (int i = 0; i < 4; ++i) {
bytes[i] = (byte)(ipAddress >> ((3 - i) * 8));
}
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append((b & 0xFF)).append(".");
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
要调用这段代码并获得Wifi的 IP 地址,只需传入一个有效的 Context
对象作为参数即可。
当然获取wifi网络还有其他方法,可以继续往下看看。
3、获取有线网的ip
//获取有线网的ip地址
public static String getEthernetIpAddress(Context context) {
LogUtil.debugInform("");
final Network network = getFirstEthernet(context);
if (network == null) {
return "";
}
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
if (linkProperties != null) {
for (LinkAddress linkAddress : linkProperties.getLinkAddresses()) {
InetAddress inetAddress = linkAddress.getAddress();
if (inetAddress instanceof Inet4Address) {
return inetAddress.getHostAddress();
}
}
}
return "";
}
private static Network getFirstEthernet(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final Network[] networks = connectivityManager.getAllNetworks();
for (final Network network : networks) {
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
//关键:判断网络类型 有线网
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {
return network;
}
}
return null;
}
使用这个方法也可以获取wifi的ip地址;修改成wifi类型判断就行了。
使用这个方法必须保证已经连接上了这个网才能查到对应的类型的ip。
网络类型定义:
package\modules\Connectivity\framework\src\android\net\ConnectivityManager.java
public static final int TYPE_MOBILE = 0; //SIM卡 网络
public static final int TYPE_WIFI = 1; //wifi 网络
public static final int TYPE_MOBILE_MMS = 2;
public static final int TYPE_MOBILE_SUPL = 3;
public static final int TYPE_MOBILE_DUN = 4;
public static final int TYPE_MOBILE_HIPRI = 5;
public static final int TYPE_WIMAX = 6;
public static final int TYPE_BLUETOOTH = 7;
public static final int TYPE_DUMMY = 8;
public static final int TYPE_ETHERNET = 9;//有线网网络
4、Android 代码获取所有网络节点的ip地址和MAC地址:
热点没有相关暴露获取的api;
Android 热点ip地址 IpServer 和相关的类都是隐藏的所以无法上Wifi那样通过api获取到ip地址;
但是可以通过遍历节点的数据,获取到ip地址,
wifi、有线网、热点的ip地址和节点相关的信息都可以这样获取到:
/**
* 获取ip地址,key为网络端口名称,比如wlan0、eth0、ap0等,value为ip地址,以及节点相关的MAC地址
*
* @return 键值对
*/
private HashMap<String, String> getNetIPs() {
HashMap<String, String> hashMap = new HashMap<>();
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement(); //打印的信息和 ifconfig 的大致对应
Log.i(TAG, "----》getEtherNetIP inf = " + intf); //eth0、wifi...
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
Log.i(TAG, "----》getEtherNetIP intf.getName() = " + intf.getName());
Log.i(TAG, "----》getEtherNetIP inetAddress = " + inetAddress);
Log.i(TAG, "----》getEtherNetIP inetAddress getHostAddress = " + inetAddress.getHostAddress());
byte[] hardwareAddress = intf.getHardwareAddress();
//节点对应的ip地址
hashMap.put(intf.getName(), "" + inetAddress.getHostAddress());
//节点对应的MAC地址,mac地址是byte数值数据,要转换成字符串
String mac = bytesToString(hardwareAddress);
hashMap.put(intf.getName() + "-MAC", "" + mac);
}
}
}
} catch (SocketException ex) {
Log.e(TAG, "getEtherNetIP = " + ex.toString());
}
return hashMap;
}
//字节数据转换成字符串
public static String bytesToString(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return null;
}
StringBuilder buf = new StringBuilder();
for (byte b : bytes) {
buf.append(String.format("%02X:", b));
}
if (buf.length() > 0) {
buf.deleteCharAt(buf.length() - 1);
}
return buf.toString();
}
所以下面这个方法对于很多场景都是可用的。
上面方法在节点名称保存了ip地址和对应的MAC地址;
可以根据需求进行适当修改处理。
上面是获取了ifconfig信息 节点上 Inet4Address 类型的所有信息。
如果只要获取热点的ip地址,可以这样写:
Android 代码获取热点的 ip地址:
主要代码:
/**
* 获取热点ip地址字符串
*/
private String getHotspottIPs() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement(); //打印的信息和 ifconfig 的大致对应
Log.i(TAG, "----》getEtherNetIP inf = " + intf); //eth0、wifi...
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address && "ap0".equals(intf.getName())) { //判断热点的节点名称ap0,如果不是ap0,就自己修改
return "" + inetAddress.getHostAddress();
}
}
}
} catch (SocketException ex) {
Log.e(TAG, "getEtherNetIP = " + ex.toString());
}
return "";
}
上面的获取热点ip的方法,是不用Context对象,不用权限,
普通应用就能调用和获取到信息,验证过是ok的。
所以WiFi、有线网这些网络的ip地址也可以参考这样获取;
需要知道当前系统网络的节点的具体情况,热点节点不一定用ap0,也有的系统使用wlan1的。
三、其他
1、ip地址获取小结
adb shell ifconfig 可以看到当前设备网络节点情况。
获取网络ip的方式有几种:
1、获取wifi 的ip
可以通过 WifiManager 获取当前连接的wifi信息,获取到ip地址;
2、获取有线网、wifi的ip
通过获取 ConnectivityManager获取连接的网络 Network-->LinkProperties获取到ip地址。
3、获取有线网、wifi、热点、p2p的ip
通过获取所有节点信息:NetworkInterface.getNetworkInterfaces() 获取对应的ip地址和MAC地址。
前面两种方式都是需要相应权限的,第二种估计要系统签名才可以获取到;
只有第三种不需要任何权限,普通应用就可以获取到;
但是第一和第二种方式是不需要知道节点名称的,第三种是需要知道节点名称的;
所以如果有系统权限,第一和第二种方式,对于所有平台方案都是可用的;
第三种方案可能对于不同平台方案要进行适配;
因为不同平台的热点和有线网等网络的节点可能不同,但是大部分都是相同的。
第三种方式是信息量最多的。
2、热点开启流程
系统源码追踪:
1、ConnectivityManager.startTethering
2、TetheringManager.startTethering
3、TetheringService.TetheringConnector.startTethering
4、Tethering.startTethering(request, listener);
5、WifiManager.startTetheredHotspot(null /* use existing softap config */)
6、WifiServiceImpl.startTetheredHotspot(@Nullable SoftApConfiguration softApConfig)
7、ActiveModeWarden.startSoftAp(apModeConfig);
8、ActiveModeManager.start();
10、WifiNative.startSoftAp
11、HostapdHal.addAccessPoint
热点开启流程原文链接:
https://blog.csdn.net/wenzhi20102321/article/details/128473734