九、热点模式(SoftAp):SoftApManager、热点配置、客户端管理

热点模式,说白了就是把手机变成一台小路由器。我刚开始接触 Android Wi-Fi 时,觉得这功能不就是开个热点嘛,有什么难的?直到自己动手写代码才发现,这里面的门道还真不少。

今天我们就来聊聊 SoftAp 的核心实现。我会从 SoftApManager 说起,再到热点配置,最后聊聊客户端管理。嗯,这些都是我在实际项目中踩过坑的地方。

9.1 SoftApManager:热点的总指挥

SoftApManager 是 Android 系统中管理热点模式的核心类。它负责启动、关闭热点,以及处理各种状态回调。

我个人习惯把 SoftApManager 看作一个状态机。它主要有这么几个状态:

  • IDLE:空闲状态,热点未启动
  • STARTING:正在启动中
  • RUNNING:热点已启动,正常运行
  • STOPPING:正在关闭中

来看看它的核心接口长什么样:

// SoftApManager 的核心接口
public class SoftApManager {
    
    // 启动热点
    public void startSoftAp(WifiConfiguration config);
    
    // 关闭热点
    public void stopSoftAp();
    
    // 更新热点配置
    public void updateSoftApConfig(WifiConfiguration config);
    
    // 获取当前客户端列表
    public List<WifiClient> getConnectedClients();
    
    // 注册状态回调
    public void registerCallback(SoftApCallback callback);
}

这里要注意一点:startSoftAp 和 stopSoftAp 都是异步操作。你不能调完 startSoftAp 就立刻认为热点已经启动了。我曾经犯过这个错误,在启动热点后马上尝试获取客户端列表,结果当然是空列表。

⚠️ 注意:热点启动和关闭都是异步操作。一定要通过回调来确认状态变更完成,不要用 Thread.sleep 这种粗暴方式。

9.2 热点配置:SSID、密码与频段

热点配置主要涉及三个东西:SSID(热点名称)、密码、频段。Android 提供了 WifiConfiguration 类来封装这些信息。

来看看一个典型的热点配置:

// 创建一个热点配置
WifiConfiguration config = new WifiConfiguration();
config.SSID = "MyHotspot_5G";
config.preSharedKey = "password123";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);

// 设置频段(5GHz)
config.apBand = WifiConfiguration.AP_BAND_5GHZ;
config.apChannel = 149;  // 指定信道

这里有几个坑,我一个个说:

  • SSID 不要用中文:虽然 Android 支持 UTF-8 编码的 SSID,但很多旧设备不兼容。我建议只用 ASCII 字符。
  • 密码长度至少 8 位:WPA2-PSK 要求密码长度在 8-63 位之间。短了会直接报错。
  • 频段选择要谨慎:5GHz 频段速度快但穿墙差,2.4GHz 覆盖广但干扰多。我一般会根据场景动态选择。
💡 小技巧:如果你想让热点兼容性好,优先选 2.4GHz。如果追求速度且设备支持,选 5GHz。我个人在项目中会提供一个配置选项让用户自己选。

9.3 客户端管理:谁连了我的热点?

热点启动后,我们需要知道有哪些设备连接了上来。Android 提供了 WifiClient 类来表示每个连接的客户端。

获取客户端列表的方式:

// 获取已连接的客户端
List<WifiClient> clients = softApManager.getConnectedClients();
for (WifiClient client : clients) {
    String macAddress = client.getMacAddress();
    String deviceName = client.getDeviceName();
    Log.d(TAG, "客户端: " + deviceName + " (" + macAddress + ")");
}

这里有个问题:getMacAddress 在 Android 10 之后被限制了。系统不再返回真实的 MAC 地址,而是返回一个随机化的地址。这是为了保护用户隐私。

我曾经在做一个企业级热点管理应用时,就因为这个限制折腾了好几天。最后我们换了个思路:用 IP 地址 + 设备名称来标识客户端。

📌 核心要点:
  • 客户端管理依赖回调机制,不要轮询
  • MAC 地址在 Android 10+ 被随机化,别太依赖它
  • 客户端断开连接时,系统会回调 onClientDisconnected

9.4 状态回调与生命周期

SoftApManager 通过回调来通知外部状态变化。典型的回调接口长这样:

public interface SoftApCallback {
    // 热点状态变化
    void onStateChanged(int state, int reason);
    
    // 有客户端连接
    void onClientConnected(WifiClient client);
    
    // 有客户端断开
    void onClientDisconnected(WifiClient client);
    
    // 热点配置变化
    void onConfigChanged(WifiConfiguration config);
}

嗯,这里要特别注意 onStateChanged 的 reason 参数。它告诉你热点为什么状态变化。比如:

  • REASON_START_FAILURE:启动失败,可能是硬件不支持
  • REASON_INTERNAL_ERROR:内部错误,比如 Wi-Fi 芯片挂了
  • REASON_CONCURRENT_CONNECTION:同时连接数超限

我建议你在开发时把这些 reason 都打日志记录下来。排查问题时会非常有帮助。

9.5 知识体系总览

下面这张图展示了 SoftAp 模式的核心知识结构:

SoftAp 热点模式知识体系 SoftApManager 热点配置 客户端管理 状态机:IDLE → STARTING → RUNNING 异步操作:start/stop 需回调确认 回调机制:onStateChanged SSID:ASCII字符,避免中文 密码:WPA2-PSK,8-63位 频段:2.4GHz vs 5GHz 选择 WifiClient:MAC + 设备名 MAC 随机化(Android 10+) 连接/断开回调 核心:状态管理 + 配置控制 + 客户端追踪

9.6 避坑指南

最后,我把自己在项目中踩过的坑总结一下:

  1. 不要在主线程操作热点:热点启动和关闭都是耗时操作,一定要在后台线程执行。
  2. 注意权限声明:Android 10 之后需要 ACCESS_FINE_LOCATION 权限才能扫描和连接热点。
  3. 处理并发场景:如果同时有多个应用在操作热点,可能会出现冲突。我建议用单线程的 Handler 来串行化操作。
  4. 测试要覆盖异常场景:比如飞行模式、Wi-Fi 关闭、硬件不支持等情况。
💡 个人经验:我曾经在做一个车载系统时,发现热点启动后客户端连接不上。排查了半天,结果是频段设置成了 5GHz,但车机的 Wi-Fi 芯片只支持 2.4GHz。从那以后,我每次都会先检查硬件能力再设置频段。

好了,关于 SoftAp 模式的核心内容就这些。热点管理看似简单,但要做好其实不容易。多测试、多打日志、多考虑边界情况,这是我一直以来的习惯。


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