You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在现代Android设备上程序化识别本地热点接口并获取相关信息?

问题描述

我需要扫描自己手机热点的连接设备,以此仅和这些设备通信,核心需要广播地址,连接设备的IP地址这类关联信息也可以。

在我的设备上操作很简单:热点对应的NetworkInterface固定是wlan1(主WiFi接口是wlan0),很容易获取IP相关信息。但其他设备的热点接口名称可能变化,比如ap0/ap1;更麻烦的是,有些机型在WiFi和热点同时开启时,接口是wlan0(WiFi)和wlan1(热点),但关闭WiFi后,热点接口会变成wlan0!

我目前的代码如下:

for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
    InetAddress inetAddress = enumIpAddr.nextElement();
    if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
        String ipadd = inetAddress.getHostAddress();
        if (name.equals("wlan0") || name.equals("wlan1"))
        {
            System.out.println("Found WLAN= " + name);
            System.out.println("IP Address = " + ipadd);
            for (InterfaceAddress interfaceAddress : intf.getInterfaceAddresses()) {
                if (interfaceAddress != null) {
                    InetAddress broadcastadd = interfaceAddress.getBroadcast();
                    if (broadcastadd != null) {
                        found_bcast_address = broadcastadd.toString();
                        found_bcast_address = found_bcast_address.substring(1);
                        System.out.println("Broadcast Address = " + found_bcast_address);
                    }
                }
            }
        }
    }
}

现在的核心问题是无法确定哪个接口对应热点,导致发送广播时无法区分响应设备是连我热点的,还是我手机连的WiFi里的设备。

之前查到的两种方案在现代Android里都失效了:

  • 读取/proc/net/arp文件:现代Android系统不可行
  • 反射调用getWifiApConfiguration:该方法在新版本Android中已无法使用

请问在近期的Android系统中,有没有可行的方法获取这些信息?


可行解决方案

针对Android 10及以上版本,可以通过以下两种可靠方式区分热点接口并获取所需信息:

1. 利用NetworkCapabilities判断热点接口

通过ConnectivityManager获取所有活跃网络,再检查网络的NetworkCapabilities特征,结合私网IP段确认热点接口:

ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
for (Network network : cm.getAllNetworks()) {
    NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
    if (capabilities != null 
        && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        && !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
        LinkProperties linkProps = cm.getLinkProperties(network);
        if (linkProps != null) {
            String ifaceName = linkProps.getInterfaceName();
            for (LinkAddress addr : linkProps.getLinkAddresses()) {
                InetAddress inetAddr = addr.getAddress();
                if (inetAddr instanceof Inet4Address && !inetAddr.isLoopbackAddress()) {
                    String ip = inetAddr.getHostAddress();
                    // 根据子网掩码计算广播地址
                    int prefixLength = addr.getPrefixLength();
                    byte[] ipBytes = inetAddr.getAddress();
                    byte[] mask = new byte[4];
                    int bits = 0xFFFFFFFF << (32 - prefixLength);
                    mask[0] = (byte) ((bits >> 24) & 0xFF);
                    mask[1] = (byte) ((bits >> 16) & 0xFF);
                    mask[2] = (byte) ((bits >> 8) & 0xFF);
                    mask[3] = (byte) (bits & 0xFF);
                    
                    byte[] broadcastBytes = new byte[4];
                    for (int i = 0; i < 4; i++) {
                        broadcastBytes[i] = (byte) (ipBytes[i] | (~mask[i] & 0xFF));
                    }
                    InetAddress broadcastAddr = InetAddress.getByAddress(broadcastBytes);
                    
                    System.out.println("热点接口: " + ifaceName);
                    System.out.println("IP地址: " + ip);
                    System.out.println("广播地址: " + broadcastAddr.getHostAddress());
                }
            }
        }
    }
}

注意:需添加权限android.permission.ACCESS_NETWORK_STATE,Android 12及以上还需android.permission.ACCESS_WIFI_STATE。

2. 通过WifiManager获取热点状态及IP信息

结合热点开启状态,利用DhcpInfo获取网关和子网掩码,推导广播地址并匹配对应接口:

WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (wifiManager.isWifiApEnabled()) {
    DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
    if (dhcpInfo != null) {
        // 转换热点网关(手机自身热点IP)为字符串格式
        int ipInt = dhcpInfo.serverAddress;
        String ip = String.format("%d.%d.%d.%d",
                (ipInt & 0xff),
                (ipInt >> 8 & 0xff),
                (ipInt >> 16 & 0xff),
                (ipInt >> 24 & 0xff));
        // 转换子网掩码为字符串格式
        int maskInt = dhcpInfo.netmask;
        String mask = String.format("%d.%d.%d.%d",
                (maskInt & 0xff),
                (maskInt >> 8 & 0xff),
                (maskInt >> 16 & 0xff),
                (maskInt >> 24 & 0xff));
        // 计算广播地址
        byte[] ipBytes = InetAddress.getByName(ip).getAddress();
        byte[] maskBytes = InetAddress.getByName(mask).getAddress();
        byte[] broadcastBytes = new byte[4];
        for (int i = 0; i < 4; i++) {
            broadcastBytes[i] = (byte) (ipBytes[i] | (~maskBytes[i] & 0xFF));
        }
        String broadcastAddr = InetAddress.getByAddress(broadcastBytes).getHostAddress();
        
        System.out.println("热点IP: " + ip);
        System.out.println("广播地址: " + broadcastAddr);
        
        // 遍历NetworkInterface找到对应接口
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface intf = interfaces.nextElement();
            Enumeration<InetAddress> addrs = intf.getInetAddresses();
            while (addrs.hasMoreElements()) {
                InetAddress addr = addrs.nextElement();
                if (addr.getHostAddress().equals(ip)) {
                    System.out.println("热点接口名称: " + intf.getName());
                    break;
                }
            }
        }
    }
}

注意:Android 10及以上需要android.permission.ACCESS_FINE_LOCATION权限,需完成动态权限申请流程。

扫描热点连接设备

获取广播地址后,可通过发送UDP广播包到该地址并监听响应,来发现已连接的设备;部分机型也可通过反射读取系统ARP缓存,但UDP广播的兼容性更优。


内容的提问来源于stack exchange,提问作者Marcello Carrozzino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 17:18:21