8. WiFi热点信息获取:获取当前连接WiFi的SSID、BSSID、IP地址、链路速度、信号强度(RSSI)、频率

做WiFi开发,第一步要干什么?

我个人习惯,先搞清楚当前连的是哪个热点。就像你打电话,总得知道对方是谁吧?

这一章,我们就来聊聊怎么从Android系统里,把这些信息“掏”出来。

8.1 我们能拿到哪些信息?

先列个清单,看看Android到底给了我们什么。

信息项 含义 典型值
SSID WiFi的名字,你看到的那个“我家WiFi” "MyHome_5G"
BSSID 路由器的MAC地址,唯一标识 "a4:5e:60:xx:xx:xx"
IP地址 手机在当前局域网内的地址 "192.168.1.101"
链路速度 当前连接的理论最大速率,单位Mbps 866
信号强度(RSSI) 接收信号强度,单位dBm -55
频率 工作在2.4GHz还是5GHz 5180 (MHz)

这些信息,说白了就是WiFi的“身份证”和“体检报告”。

8.2 核心API:WifiManager 和 WifiInfo

获取这些信息,主要靠两个类:WifiManagerWifiInfo

WifiManager 是系统WiFi服务的管理员,WifiInfo 就是当前连接的详细档案。

获取 WifiManager 实例的代码,我猜你已经很熟了:

WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

然后,拿到 WifiInfo

WifiInfo wifiInfo = wifiManager.getConnectionInfo();

嗯,这里要注意。从Android 10开始,系统对WiFi信息的访问权限收紧了。如果你直接这么拿,可能会拿到 null 或者假的SSID(比如一堆0)。

权限警告:

从Android 10 (API 29) 开始,获取SSID和BSSID需要 ACCESS_FINE_LOCATION 权限,并且需要用户开启位置服务。否则,getSSID() 会返回 "<unknown ssid>"

我曾经在一个项目中,忘了处理这个情况,结果用户反馈说“WiFi名字全是乱码”。排查了半天,才发现是权限没到位。

8.3 逐个击破:获取每一项信息

拿到 WifiInfo 对象后,事情就简单了。每个信息都有对应的getter方法。

8.3.1 SSID 和 BSSID

String ssid = wifiInfo.getSSID();
String bssid = wifiInfo.getBSSID();

注意,getSSID() 返回的字符串可能带双引号,比如 "\"MyHome\""。你想想看,这多坑。所以拿到后最好处理一下:

if (ssid != null && ssid.startsWith("\"") && ssid.endsWith("\"")) {
    ssid = ssid.substring(1, ssid.length() - 1);
}

8.3.2 IP地址

这个有点绕。getIpAddress() 返回的是一个int值,不是我们常见的点分十进制字符串。

int ipInt = wifiInfo.getIpAddress();
String ipString = String.format("%d.%d.%d.%d",
        (ipInt & 0xff),
        (ipInt >> 8 & 0xff),
        (ipInt >> 16 & 0xff),
        (ipInt >> 24 & 0xff)
);

为什么Android要这么设计?我猜是为了效率。但对我们开发者来说,确实不太友好。

8.3.3 链路速度

int linkSpeed = wifiInfo.getLinkSpeed(); // 单位 Mbps

这个值代表的是当前连接的理论最大速率。实际传输速度通常会低一些。我在测试时发现,866Mbps的链接,实际跑文件传输也就400-500Mbps左右。

8.3.4 信号强度 (RSSI)

int rssi = wifiInfo.getRssi(); // 单位 dBm

RSSI是负数,值越大(越接近0)信号越好。比如 -30dBm 就是满格,-80dBm 基本就快断了。

Android还提供了一个工具方法,可以把RSSI换算成我们常见的信号格数:

int level = WifiManager.calculateSignalLevel(rssi, 5); // 5格信号
经验之谈:

RSSI受环境影响很大。你拿着手机转个身,数值可能就跳变10个dBm。所以做信号监测时,我建议做个滑动平均,别直接用原始值。

8.3.5 频率

int frequency = wifiInfo.getFrequency(); // 单位 MHz

通过频率,我们可以判断是2.4G还是5G:

boolean is5GHz = frequency > 4900 && frequency < 5900;
boolean is24GHz = frequency > 2400 && frequency < 2500;

为什么不用 is5GHz() 方法?因为那个方法在API 21才加入,而且有些厂商实现有问题。我自己更习惯用频率范围来判断,兼容性更好。

8.4 完整代码示例

把上面这些串起来,就是一个完整的工具类:

public class WifiInfoHelper {

    public static WifiInfoBean getCurrentWifiInfo(Context context) {
        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        if (wifiManager == null) return null;

        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        if (wifiInfo == null) return null;

        WifiInfoBean bean = new WifiInfoBean();

        // SSID
        String ssid = wifiInfo.getSSID();
        if (ssid != null && ssid.startsWith("\"") && ssid.endsWith("\"")) {
            ssid = ssid.substring(1, ssid.length() - 1);
        }
        bean.ssid = ssid;

        // BSSID
        bean.bssid = wifiInfo.getBSSID();

        // IP地址
        int ipInt = wifiInfo.getIpAddress();
        bean.ipAddress = String.format("%d.%d.%d.%d",
                (ipInt & 0xff),
                (ipInt >> 8 & 0xff),
                (ipInt >> 16 & 0xff),
                (ipInt >> 24 & 0xff)
        );

        // 链路速度
        bean.linkSpeed = wifiInfo.getLinkSpeed();

        // RSSI
        bean.rssi = wifiInfo.getRssi();

        // 频率
        bean.frequency = wifiInfo.getFrequency();

        return bean;
    }

    public static class WifiInfoBean {
        public String ssid;
        public String bssid;
        public String ipAddress;
        public int linkSpeed;
        public int rssi;
        public int frequency;
    }
}

8.5 知识体系图

为了让你更直观地理解整个流程,我画了一张图:

WiFi热点信息获取流程 Context WifiManager WifiInfo SSID BSSID IP地址 链路速度 RSSI 频率

8.6 避坑指南

最后,分享几个我踩过的坑:

  • 权限问题:Android 10以上,别忘了申请 ACCESS_FINE_LOCATION,并且引导用户开启位置开关。
  • 空指针:WiFi没连接时,getConnectionInfo() 返回的对象里,很多字段是无效值。比如SSID可能是 null,RSSI可能是 -127。记得做判空。
  • 线程问题:这些API调用很快,但如果你在子线程里操作,记得确保 Context 是Application级别的,避免内存泄漏。
  • 厂商差异:有些国产手机对 getFrequency() 的实现有bug,返回0。遇到这种情况,我一般会加个兜底逻辑,从扫描结果里再查一次。

好了,这一章的内容就到这里。信息获取是WiFi开发的基础,把这些搞扎实了,后面的操作才能得心应手。


公众号:蓝海资料掘金营,微信deep3321