6、连接管理(Connect):网络配置、连接状态机、认证与关联
大家好,我是你们的老朋友。今天我们来聊聊 Wi-Fi 连接管理中最核心的部分——连接管理。说白了,就是 Android 设备怎么从一堆网络里选一个,然后连上去,最后能正常上网。
我个人习惯把连接管理拆成三个层面来看:网络配置(你要连谁?)、连接状态机(连的过程怎么走?)、认证与关联(怎么证明你是你?)。这三个东西串起来,就是一次完整的连接流程。
核心要点:连接管理不是简单的“点一下就连”,而是一个多步骤、多状态、多回调的复杂过程。理解它,你才能写出稳定、高效的 Wi-Fi 应用。
6.1 网络配置(WifiConfiguration)
先说说 WifiConfiguration。这个类,说白了就是 Wi-Fi 网络的“身份证”。它记录了网络的所有关键信息:SSID、密码、加密类型、优先级、是否隐藏等等。
我在项目中遇到过一个问题:用户明明输入了正确的密码,但就是连不上。后来发现,是 WifiConfiguration 的 allowedKeyManagement 字段没设置对。嗯,这里要注意,不同加密方式对应不同的 key management 值。
| 加密类型 | allowedKeyManagement 值 | 说明 |
|---|---|---|
| 无加密 | KeyMgmt.NONE | 开放网络,不推荐 |
| WPA-PSK | KeyMgmt.WPA_PSK | 个人模式,最常见 |
| WPA-EAP | KeyMgmt.WPA_EAP | 企业模式,需要 802.1X |
| WPA2-PSK | KeyMgmt.WPA_PSK | 兼容 WPA-PSK |
| WPA3-SAE | KeyMgmt.SAE | 新一代安全标准 |
创建 WifiConfiguration 的代码其实很简单,但坑不少。我给大家看一个我常用的模板:
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"MyWiFi\""; // 注意:SSID 必须带双引号
config.preSharedKey = "\"password123\""; // 密码也要带双引号
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN); // WPA2
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.hiddenSSID = false; // 如果是隐藏网络,设为 true
config.priority = 1; // 优先级,数值越大越优先
避坑指南:我曾经因为忘记给 SSID 和密码加双引号,导致连接失败。Android 框架内部会解析这些字符串,不加引号会直接报错。记住:SSID = "\"MyWiFi\"",不是 SSID = "MyWiFi"。
6.2 连接状态机
连接状态机,是 Wi-Fi 连接管理的“大脑”。它定义了连接过程中各个状态的流转。你想想看,从用户点击连接,到最终连上网络,中间要经历多少步?
Android 的 Wi-Fi 状态机(WifiStateMachine)是一个有限状态机,主要状态包括:
- Disconnected:初始状态,未连接任何网络
- Connecting:正在尝试连接,发送关联请求
- Authenticating:正在进行认证(如 WPA 四次握手)
- ObtainingIpAddress:正在获取 IP 地址(DHCP)
- Connected:连接成功,可以上网
- Disconnecting:正在断开连接
我个人习惯把状态机画成一张图,这样理解起来更直观。下面是我用 SVG 画的一张简化版连接状态机流程图:
这张图展示了从 Disconnected 到 Connected 的完整路径。每个状态之间都有明确的触发条件。比如,从 Connecting 到 Authenticating,前提是关联(Association)成功。
注意:状态机不是单向的。任何状态都可能因为超时、错误或用户操作而回退到 Disconnected。我曾经调试过一个 bug,设备在 ObtainingIpAddress 状态卡了 30 秒,然后直接跳回 Disconnected。后来发现是 DHCP 服务器响应太慢。
6.3 认证与关联
认证和关联,是连接过程中最“技术”的两个环节。很多人把它们混为一谈,其实它们是两个不同的步骤。
关联(Association):设备向 AP 发送关联请求,AP 回复关联响应。这一步只是建立了一个“初步连接”,还没有验证身份。
认证(Authentication):在关联之后,设备需要证明自己有权限访问这个网络。对于 WPA/WPA2,就是四次握手(4-Way Handshake)。
我给大家画一个认证过程的时序图,这样更清楚:
四次握手的核心,就是通过交换随机数(Nonce)和密钥材料,生成一个双方都认可的会话密钥(PTK)。之后的所有数据都用这个密钥加密。
避坑指南:我曾经遇到过一个情况,设备连上 AP 后,过几秒就断开了。抓包发现,是四次握手的 Msg 3 丢失了。AP 重传了几次,但设备没有正确处理重传包。解决方案是:在代码中增加对 EAPOL 帧的超时重传处理。
对于企业级网络(WPA-EAP),认证过程更复杂,涉及 RADIUS 服务器和 802.1X 协议。但核心逻辑是一样的:先关联,再认证,最后加密通信。
6.4 实战建议
说了这么多理论,最后给大家几个实战建议:
- 监听连接状态变化:使用
WifiManager.NETWORK_STATE_CHANGED_ACTION广播,或者ConnectivityManager.NetworkCallback,实时跟踪连接状态。 - 处理配置冲突:如果多个 WifiConfiguration 有相同的 SSID 但不同的安全设置,系统可能会混乱。建议在添加配置前,先删除同名的旧配置。
- 注意权限:从 Android 10 开始,位置权限和
ACCESS_FINE_LOCATION是必须的。别问我怎么知道的,我踩过这个坑。 - 测试弱网环境:连接管理在信号弱、干扰大的环境下最容易出问题。建议用 Wi-Fi 信号模拟器测试各种边界情况。
好了,关于连接管理的内容就讲到这里。记住:网络配置是基础,状态机是骨架,认证与关联是灵魂。把这三块吃透了,你就能写出稳定可靠的 Wi-Fi 连接代码。