6、连接WiFi(传统方式):WifiConfiguration配置、addNetwork与enableNetwork、连接开放网络与WPA2/WPA3网络

说到WiFi连接,很多新手第一反应就是「直接调用系统API不就行了?」。嗯,理论上确实如此,但实际项目中你会发现,坑比想象中多得多。今天我就带你手把手走一遍传统连接方式的完整流程。

6.1 传统连接方式的核心思路

在Android 10之前,连接WiFi主要靠三个步骤:

  • 创建一个WifiConfiguration对象,填好SSID和密码
  • 调用addNetwork()把配置添加到系统
  • 调用enableNetwork()让系统去连接这个网络

说白了,就是「先注册,再启用」。我刚开始做WiFi开发时,以为这跟连蓝牙一样简单,结果第一次测试就翻车了——明明配置对了,手机就是不连。后来才发现,是networkId没处理好。

核心要点:传统方式虽然代码量不大,但细节决定成败。尤其是Android碎片化严重,不同厂商的定制ROM行为可能不一样。

6.2 WifiConfiguration配置详解

WifiConfiguration是连接WiFi的「身份证」。你需要告诉系统:这个WiFi叫什么名字、用什么加密方式、密码是多少。

我个人习惯把配置过程封装成一个工具方法,这样复用起来方便。来看一个开放网络的配置示例:

private WifiConfiguration createOpenNetworkConfig(String ssid) {
    WifiConfiguration config = new WifiConfiguration();
    config.SSID = "\"" + ssid + "\"";
    config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    return config;
}

注意SSID必须用双引号包起来。我见过不少新手直接传config.SSID = ssid,结果死活连不上。为什么?因为系统解析时会把不带引号的SSID当成无效值。

再看WPA2/WPA3网络的配置:

private WifiConfiguration createSecureNetworkConfig(String ssid, String password, boolean isWpa3) {
    WifiConfiguration config = new WifiConfiguration();
    config.SSID = "\"" + ssid + "\"";
    config.preSharedKey = "\"" + password + "\"";
    
    if (isWpa3) {
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
        config.requirePMF = true;  // WPA3必须启用PMF
    } else {
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
    }
    
    return config;
}

这里有个坑:WPA3用的是SAE(Simultaneous Authentication of Equals)协议,而不是传统的WPA_PSK。我在项目中遇到过一台小米手机,明明支持WPA3,但配置时忘了设requirePMF,结果一直连不上。查了半天文档才发现,WPA3强制要求PMF(Protected Management Frames)为true。

⚠️ 重要提醒:WPA3的配置项在不同Android版本上表现不一致。Android 10以上才完整支持SAE,低版本建议做兼容处理。

6.3 addNetwork与enableNetwork的配合

配置好WifiConfiguration之后,下一步就是把它交给系统。流程是这样的:

  1. 调用wifiManager.addNetwork(config),返回一个networkId
  2. 如果networkId为-1,说明添加失败
  3. 调用wifiManager.enableNetwork(networkId, true),第二个参数表示禁用其他网络
  4. 调用wifiManager.reconnect()触发重连

来看完整代码:

public boolean connectToWiFi(Context context, String ssid, String password, boolean isWpa3) {
    WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    
    // 1. 创建配置
    WifiConfiguration config = createSecureNetworkConfig(ssid, password, isWpa3);
    
    // 2. 添加网络
    int networkId = wifiManager.addNetwork(config);
    if (networkId == -1) {
        Log.e("WiFiConnect", "添加网络失败,请检查SSID或密码");
        return false;
    }
    
    // 3. 启用网络
    boolean enabled = wifiManager.enableNetwork(networkId, true);
    if (!enabled) {
        Log.e("WiFiConnect", "启用网络失败");
        return false;
    }
    
    // 4. 触发重连
    boolean reconnected = wifiManager.reconnect();
    return reconnected;
}

你想想看,为什么需要reconnect()?因为enableNetwork只是告诉系统「我想连这个」,但系统不一定会立即执行。加上reconnect()相当于推了一把。

💡 个人经验:我曾经在三星平板上遇到过enableNetwork返回true但实际没连上的情况。后来加了个延时再检查连接状态,问题就解决了。建议在reconnect()之后,用BroadcastReceiver监听WifiManager.NETWORK_STATE_CHANGED_ACTION来确认连接结果。

6.4 连接开放网络与WPA2/WPA3的差异

不同加密方式的连接逻辑,其实就体现在WifiConfiguration的配置上。我整理了一张对比表:

网络类型 KeyMgmt设置 preSharedKey 额外要求
开放网络 KeyMgmt.NONE 不需要
WPA2 KeyMgmt.WPA_PSK 密码(双引号包裹)
WPA3 KeyMgmt.SAE 密码(双引号包裹) requirePMF = true
WPA2/WPA3混合 KeyMgmt.WPA_PSK + KeyMgmt.SAE 密码(双引号包裹) 需同时设置两种KeyMgmt

对于混合模式,配置代码要这样写:

config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
config.requirePMF = true;

嗯,这里要注意:混合模式下,系统会自动选择最合适的加密方式。但有些老旧路由器虽然广播了WPA3,实际却不支持,这时候手机会降级到WPA2连接。

6.5 知识体系总览

下面这张图帮你理清传统WiFi连接的完整脉络:

传统WiFi连接流程 1. 创建WifiConfiguration 设置SSID、加密方式 设置密码/KeyMgmt 2. addNetwork() 返回networkId -1表示失败 3. enableNetwork() 传入networkId disableOthers=true 4. reconnect() 触发系统执行连接 5. 监听连接结果 BroadcastReceiver 加密方式配置 • 开放网络:KeyMgmt.NONE • WPA2:KeyMgmt.WPA_PSK • WPA3:KeyMgmt.SAE + requirePMF=true • 混合:同时设置WPA_PSK 和SAE

6.6 避坑指南

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

  • SSID必须带引号:这是最容易被忽略的。系统内部存储时会把引号去掉,但传入时必须加上。
  • networkId会变化:如果之前已经添加过同一个网络,addNetwork()会返回已有的networkId,而不是新建一个。所以不要假设每次返回的都是新ID。
  • 权限问题:Android 8.1以上需要ACCESS_FINE_LOCATION权限,否则getScanResults()会返回空列表。我曾在华为手机上调试了半天,最后发现是定位权限没开。
  • WPA3兼容性:不是所有Android 10以上的手机都完美支持WPA3。建议在连接前先检查设备能力,或者做降级处理。
📌 我的建议:如果你要兼容Android 10以下的设备,传统方式还是首选。但如果你的App只面向Android 10+,建议改用WifiNetworkSpecifier,那是Google推荐的新方式,代码更简洁,而且不需要CHANGE_WIFI_STATE权限。

好了,传统WiFi连接的核心内容就这些。代码量不大,但每个细节都可能让你翻车。记住:SSID加引号、networkId判-1、WPA3设PMF,这三点做到位,基本就不会出大问题。


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