WiFi配置管理:保存的网络列表、忘记网络与更新配置

各位好,今天我们来聊聊WiFi配置管理这块。说实话,这部分内容在平时开发中可能不太起眼,但一旦出了问题,排查起来特别头疼。我个人习惯把WiFi配置管理比作手机的「通讯录」——你存了谁、删了谁、改了谁的电话,都得有个清晰的逻辑。

在Android里,WiFi配置管理主要涉及三个操作:获取已保存的网络列表忘记某个网络更新已有网络的配置。这三个操作背后,其实都围绕着同一个核心对象——WifiConfiguration

1. 获取已保存的网络列表

先说说怎么拿到手机里存着的WiFi列表。这个操作很简单,调用WifiManager.getConfiguredNetworks()就行。但这里有个坑——Android 10(API 29)开始,这个方法被标记为废弃了

为什么会这样?因为Google觉得直接暴露所有已保存网络的详细信息不太安全。你想想看,如果某个恶意应用拿到了这个列表,它就能知道你常去哪些地方、连过哪些热点。所以从Android 10开始,推荐用WifiManager.getPrivilegedConfiguredNetworks(),但这个需要SYSTEM_ALERT_WINDOW权限,普通应用基本拿不到。

⚠️ 注意: 如果你的应用targetSdkVersion >= 29,直接调用getConfiguredNetworks()会返回一个空列表。我在项目中就踩过这个坑——测试同学说「为什么我的WiFi列表是空的?」排查了半天才发现是API限制。

来看一段示例代码:

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

List<WifiConfiguration> networks = wifiManager.getConfiguredNetworks();
if (networks != null) {
    for (WifiConfiguration config : networks) {
        Log.d("WiFiConfig", "SSID: " + config.SSID 
                + ", BSSID: " + config.BSSID
                + ", 优先级: " + config.priority);
    }
}

这段代码在Android 9及以下跑得挺好。但如果你要适配高版本,就得另想办法了——比如用WifiNetworkSuggestion或者干脆引导用户手动操作。

2. 忘记网络(forgetNetwork)

「忘记网络」说白了就是删除手机里保存的某个WiFi配置。调用WifiManager.forgetNetwork(int netId, ActionListener listener)即可。

这里有个细节:netId是从WifiConfiguration.networkId拿到的。每个已保存的网络都有一个唯一的ID,就像身份证号一样。我曾经在项目里犯过一个低级错误——把SSID当成了netId传进去,结果怎么都删不掉,还报了INVALID_ARGUMENT错误。

int netId = config.networkId;  // 注意:不是SSID!
wifiManager.forgetNetwork(netId, new WifiManager.ActionListener() {
    @Override
    public void onSuccess() {
        Log.d("WiFiConfig", "网络已忘记");
    }

    @Override
    public void onFailure(int reason) {
        Log.e("WiFiConfig", "忘记失败,原因码: " + reason);
    }
});
💡 小技巧: 忘记网络成功后,建议主动刷新一下UI。我一般会在onSuccess里重新调用一次getConfiguredNetworks(),确保列表是最新的。

3. 更新网络配置

更新配置的场景其实挺常见的。比如用户改了WiFi密码、或者你想调整某个热点的优先级。更新操作本质上就是「先删除旧的,再添加新的」——但Android提供了一个更优雅的方式:WifiManager.updateNetwork(WifiConfiguration config)

这个方法会返回一个int值:

返回值 含义
-1 更新失败
其他值 更新后的networkId

更新时要注意:必须保证WifiConfiguration对象里的networkId是有效的。如果你传了一个新的WifiConfiguration对象但没设置networkId,系统会认为你想添加一个新网络,而不是更新。

// 先获取已有的配置
WifiConfiguration config = findConfigBySSID("MyHomeWiFi");
if (config != null) {
    // 修改密码
    config.preSharedKey = "\"new_password_123\"";
    config.priority = 1;
    
    int result = wifiManager.updateNetwork(config);
    if (result != -1) {
        wifiManager.saveConfiguration();  // 别忘了保存!
        Log.d("WiFiConfig", "更新成功,新networkId: " + result);
    } else {
        Log.e("WiFiConfig", "更新失败");
    }
}
🔑 关键点: 调用updateNetwork()之后,必须再调用wifiManager.saveConfiguration(),否则修改不会持久化。这个步骤很容易被忽略,我刚开始做WiFi开发时就漏过好几次。

4. 知识体系总览

下面这张图把WiFi配置管理的核心逻辑串起来了:

WiFi配置管理核心流程 WifiConfiguration getConfiguredNetworks() forgetNetwork(netId) updateNetwork(config) 返回 List<WifiConfiguration> ActionListener回调 返回新networkId / -1 ⚠️ Android 10+ 限制:getConfiguredNetworks() 返回空列表 更新后必须调用 saveConfiguration() 才能持久化

5. 避坑指南

最后,我把自己这些年踩过的坑整理一下:

  • 权限问题:操作WiFi配置需要ACCESS_FINE_LOCATIONACCESS_WIFI_STATE权限。Android 10以上还需要ACCESS_BACKGROUND_LOCATION。我曾经因为没申请后台定位权限,导致在后台更新配置时直接崩溃。
  • 线程问题getConfiguredNetworks()是同步调用,不要在UI线程里执行。我习惯用AsyncTask或者协程来处理。
  • SSID格式:保存配置时,SSID必须带双引号,比如"MyWiFi"。但getConfiguredNetworks()返回的SSID可能带也可能不带引号,不同厂商的ROM行为不一致。我的处理方式是统一用WifiManager.ssidToWifiConfig()来转换。
  • saveConfiguration()已废弃:从Android 8.0开始,saveConfiguration()被标记为废弃。实际上,在Android 8.0以上,updateNetwork()会自动保存,不需要再手动调用。但为了兼容低版本,我一般还是会加上这个调用。
📌 我的建议: 如果你要做一个WiFi管理类的应用,最好把配置操作封装成一个独立的Manager类。这样既方便测试,也便于后续适配不同Android版本。我现在的项目里就是这么做的,维护起来轻松很多。

好了,关于WiFi配置管理的内容就聊到这里。这部分虽然看起来简单,但涉及到的细节和兼容性问题确实不少。希望今天的分享能帮你少走一些弯路。

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