Android 获取ip地址多种方式介绍

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

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峥嵘life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值