Wi-Fi 管理模块使用速查

Wi-Fi 管理模块使用速查

1. 连接 Wi-Fi 前先调用 startScan

鸿蒙中直接调用连接 Wi-Fi API,有时会连接失败。尤其是刚打开 Wi-Fi、刚断开其他 Wi-Fi 或系统还没有扫描结果时。

固定写法:

WifiManager.startScan();

setTimeout(() => {
  WifiManager.connect(
    ssid,
    password,
    securityType,
    (result) => {
      if (result === WifiConnectErrorCode.WIFI_CONNECT_SUCCESS) {
        console.info('Wi-Fi 连接成功');
      } else {
        console.info('Wi-Fi 连接失败: ' + result);
      }
    }
  );
}, 1000);

不要直接连接:

// 可能失败
WifiManager.connect(ssid, password, securityType, callback);

推荐流程:

打开 Wi-Fi
  -> startScan()
  -> 等待扫描完成
  -> connect()
  -> 等待 Wi-Fi 真正连接
  -> 获取网关
  -> 绑定 App 网络

2. 统一后的 Wi-Fi 管理类

以后业务层只使用一个入口:

WifiManager.startScan()
WifiManager.getScanList()
WifiManager.connect()
WifiManager.disconnect()
WifiManager.isWifiActive()
WifiManager.isWifiConnected()
WifiManager.getConnectedInfo()
WifiManager.getGateway()

WifiManager.startListen()
WifiManager.stopListen()
WifiManager.bindToCameraWifi()
WifiManager.bindToCellular()
WifiManager.withInternet()

简单理解:

WifiManager
├── Wi-Fi 基础操作
│   ├── 扫描
│   ├── 连接
│   ├── 断开
│   └── 获取 Wi-Fi 信息
└── App 网络操作
    ├── 监听网络变化
    ├── 绑定相机 Wi-Fi
    ├── 绑定蜂窝网络
    └── 临时切换网络

3. 扫描 Wi-Fi

WifiManager.startScan();

获取扫描结果:

const list = WifiManager.getScanList();

list.forEach((item) => {
  console.info(
    `ssid=${item.ssid}, rssi=${item.rssi}, securityType=${item.securityType}`
  );
});

扫描结果可能暂时为空,不要立刻判断成“没有 Wi-Fi”:

async function scanWifi(): Promise<wifiManager.WifiScanInfo[]> {
  for (let i = 0; i < 3; i++) {
    WifiManager.startScan();

    await new Promise<void>((resolve) => {
      setTimeout(resolve, 1000);
    });

    const list = WifiManager.getScanList();
    if (list.length > 0) {
      return list;
    }
  }

  return [];
}

4. 连接 Wi-Fi

WifiManager.startScan();

setTimeout(() => {
  WifiManager.connect(
    'CAMERA_WIFI_SSID',
    'CAMERA_WIFI_PASSWORD',
    3,
    (result) => {
      switch (result) {
        case WifiConnectErrorCode.WIFI_CONNECT_SUCCESS:
          console.info('连接成功');
          break;

        case WifiConnectErrorCode.USER_REFUSED:
          console.info('用户拒绝连接');
          break;

        case WifiConnectErrorCode.WIFI_CONNECT_TIMEOUT:
          console.info('连接超时');
          break;

        default:
          console.info('连接失败');
          break;
      }
    }
  );
}, 1000);

连接结果回调成功后,还要等待系统拿到 IP:

setTimeout(async () => {
  const connected = WifiManager.isWifiConnected();
  const gateway = WifiManager.getGateway();

  if (connected && gateway) {
    console.info('Wi-Fi 已真正可用');
  }
}, 2000);

5. 判断 Wi-Fi 状态

判断 Wi-Fi 开关:

if (!WifiManager.isWifiActive()) {
  ToastUtil.showToast('请打开 Wi-Fi');
  return;
}

判断是否真正连接:

if (!WifiManager.isWifiConnected()) {
  ToastUtil.showToast('Wi-Fi 尚未连接');
  return;
}

注意:

isWifiActive()     -> 只表示 Wi-Fi 开关打开
isWifiConnected()  -> 表示当前确实连上了 Wi-Fi

不能只用 isWifiActive() 判断是否已经连上网络。

获取当前 Wi-Fi:

const info = await WifiManager.getConnectedInfo();

if (info?.ssid) {
  console.info('当前 Wi-Fi: ' + info.ssid);
}

获取网关:

const gateway = WifiManager.getGateway();

console.info('当前网关: ' + gateway);

6. 判断是不是相机 Wi-Fi

相机 Wi-Fi 不建议只通过 SSID 判断,因为用户可能修改相机名称。

可以通过网关判断:

const cameraGateways = [
  'CAMERA_GATEWAY_1',
  'CAMERA_GATEWAY_2'
];

const gateway = WifiManager.getGateway();
const isCameraWifi = !!gateway && cameraGateways.includes(gateway);

完整判断:

if (
  WifiManager.isWifiConnected() &&
  WifiManager.isCameraWifi()
) {
  console.info('当前连接的是相机 Wi-Fi');
}

7. 连接成功后绑定 App 网络

手机可能同时存在:

相机 Wi-Fi
普通 Wi-Fi
蜂窝网络

Wi-Fi 连接成功,不代表 App 的请求一定走这个 Wi-Fi。相机连接成功后要绑定:

await WifiManager.bindToCameraWifi();

典型写法:

WifiManager.startScan();

setTimeout(() => {
  WifiManager.connect(
    'CAMERA_WIFI_SSID',
    'CAMERA_WIFI_PASSWORD',
    3,
    async (result) => {
      if (result !== WifiConnectErrorCode.WIFI_CONNECT_SUCCESS) {
        return;
      }

      setTimeout(async () => {
        if (!WifiManager.isCameraWifi()) {
          ToastUtil.showToast('当前不是相机 Wi-Fi');
          return;
        }

        await WifiManager.bindToCameraWifi();
        console.info('App 已绑定到相机 Wi-Fi');
      }, 2000);
    }
  );
}, 1000);

8. 相机 Wi-Fi 和蜂窝网络切换

相机 Wi-Fi 一般只能访问相机,不能访问互联网。

当 App 连接相机 Wi-Fi 后要请求云接口,使用:

await WifiManager.withInternet(async () => {
  await requestCloudData();
});

内部流程:

当前不是相机 Wi-Fi
  -> 直接请求云接口

当前是相机 Wi-Fi
  -> 临时绑定蜂窝网络
  -> 请求云接口
  -> 请求完成后切回相机 Wi-Fi

示例:

async function loadCloudFileList(): Promise<void> {
  await WifiManager.withInternet(async () => {
    await CloudRepoApi.file.getListFiles(params);
  });
}

不要在业务代码中自己来回绑定:

// 不建议
await connection.setAppNet(cellularNet);
await requestCloudData();
await connection.setAppNet(cameraWifiNet);

9. 监听网络变化

应用启动或进入需要网络管理的页面时:

WifiManager.startListen();

页面退出时:

WifiManager.stopListen();

一定要防止重复注册:

startListen(): void {
  if (this.isListening) {
    return;
  }

  this.isListening = true;
  // 注册 Wi-Fi 和蜂窝网络监听
}

否则会出现:

同一个事件触发多次
WebSocket 重复重连
断开后重复刷新页面
旧页面退出后还在执行回调

10. Wi-Fi 断开处理

Wi-Fi 断开时需要:

1. 清理旧 Wi-Fi 网络句柄
2. 更新相机连接状态
3. 断开或重连 WebSocket
4. 优先切换到蜂窝网络
5. 没有蜂窝网络时切回系统默认网络

监听 Wi-Fi 驱动状态:

const callback = (state: number): void => {
  if (state === 0) {
    console.info('Wi-Fi 已断开');
    WifiManager.handleWifiDisconnected();
  }

  if (state === 1) {
    console.info('Wi-Fi 已连接,等待 IP');
  }
};

wifiManager.on('wifiConnectionChange', callback);

相机 Wi-Fi 没有互联网是正常情况,不能只依赖 NET_CAPABILITY_VALIDATED 判断。否则蜂窝网络打开时,系统可能不触发相机 Wi-Fi 的 netLost

11. 重新连接相机 Wi-Fi

重新连接时也要先扫描:

async function reconnectCamera(): Promise<boolean> {
  WifiManager.startScan();

  await new Promise<void>((resolve) => {
    setTimeout(resolve, 2000);
  });

  const wifiList = WifiManager.getScanList();
  const cameraWifi = wifiList.find(
    (item) => item.ssid === 'CAMERA_WIFI_SSID'
  );

  if (!cameraWifi) {
    return false;
  }

  return await new Promise<boolean>((resolve) => {
    WifiManager.connect(
      cameraWifi.ssid,
      'CAMERA_WIFI_PASSWORD',
      cameraWifi.securityType,
      async (result) => {
        if (result !== WifiConnectErrorCode.WIFI_CONNECT_SUCCESS) {
          resolve(false);
          return;
        }

        setTimeout(async () => {
          const success = WifiManager.isCameraWifi();

          if (success) {
            await WifiManager.bindToCameraWifi();
          }

          resolve(success);
        }, 2000);
      }
    );
  });
}

不要只判断连接 API 返回成功,还要检查:

WifiManager.isWifiConnected()
WifiManager.getGateway()
WifiManager.isCameraWifi()

12. 删除 Wi-Fi 配置

删除当前候选网络:

await WifiManager.removeNetwork();

删除指定 SSID 的系统配置:

await WifiManager.removeNetworkBySsid('CAMERA_WIFI_SSID');

适合用于:

用户修改密码后重新连接
密码验证前清理旧配置
删除旧相机记录
避免系统自动使用旧密码连接

13. Wi-Fi 密码验证

验证密码时建议:

1. startScan()
2. 找到目标 SSID
3. 断开当前同名 Wi-Fi
4. 删除旧候选配置
5. 使用新密码连接
6. 轮询 getConnectedInfo()
7. 确认 SSID 和连接状态
const valid = await WifiManager.validatePassword(
  'CAMERA_WIFI_SSID',
  'CAMERA_WIFI_PASSWORD',
  (progress, message) => {
    console.info(`${progress}% ${message}`);
  }
);

if (valid) {
  console.info('密码正确');
} else {
  console.info('密码错误或连接超时');
}

只判断 connectToCandidateConfig() 调用成功是不够的,还要确认:

const info = await WifiManager.getConnectedInfo();

const success =
  info?.ssid === targetSsid &&
  info?.connState === wifiManager.ConnState.CONNECTED;

14. 连接失败排查顺序

1. Wi-Fi 开关是否打开
2. connect 前是否调用 startScan
3. 是否等待了扫描结果
4. SSID 是否为空或拼写错误
5. 密码是否正确
6. securityType 是否匹配
7. 是否需要用户确认
8. 是否拿到了 IP
9. 是否获取到了相机网关
10. App 是否绑定到了正确的网络句柄

最常见的修复:

WifiManager.startScan();

setTimeout(() => {
  WifiManager.connect(
    ssid,
    password,
    securityType,
    callback
  );
}, 1000);

15. 连接成功但访问相机失败

先打印:

console.info('wifi=' + WifiManager.isWifiConnected());
console.info('gateway=' + WifiManager.getGateway());

如果 Wi-Fi 已连接但网关为空,说明 DHCP 还没有完成:

setTimeout(async () => {
  await WifiManager.bindToCameraWifi();
}, 2000);

如果网关不是相机网关,说明:

连上的不是相机 Wi-Fi
系统自动连到了其他 Wi-Fi
相机热点已经断开

16. 网络管理类的推荐职责

统一后的 WifiManager 只负责网络相关事情:

负责:
- 扫描 Wi-Fi
- 连接 Wi-Fi
- 断开 Wi-Fi
- 获取 Wi-Fi 信息
- 获取网关
- 绑定 App 网络
- 切换 Wi-Fi / 蜂窝
- 监听网络状态

不建议放进去:

- 页面跳转
- 相机业务协议
- WebSocket 具体业务消息
- Toast 文案
- 下载任务
- 云相册业务逻辑

WebSocket 重连可以通过回调通知:

WifiManager.setNetworkCallback({
  onWifiConnected: () => {
    WebSocketUtil.connectSocket();
  },

  onWifiDisconnected: () => {
    WebSocketUtil.disconnectSocket();
  }
});

这样 Wi-Fi 管理类不会直接依赖云模块,basemine_cloud 也不会产生循环依赖。

17. 最简单的完整使用案例

import { WifiManager, WifiConnectErrorCode } from '@ohos/base';

async function connectCamera(): Promise<void> {
  const ssid = 'CAMERA_WIFI_SSID';
  const password = 'CAMERA_WIFI_PASSWORD';
  const securityType = 3;

  if (!WifiManager.isWifiActive()) {
    ToastUtil.showToast('请先打开 Wi-Fi');
    return;
  }

  // 连接前必须先扫描
  WifiManager.startScan();

  setTimeout(() => {
    WifiManager.connect(
      ssid,
      password,
      securityType,
      async (result) => {
        if (result !== WifiConnectErrorCode.WIFI_CONNECT_SUCCESS) {
          ToastUtil.showToast('Wi-Fi 连接失败');
          return;
        }

        // 等待系统完成 DHCP
        setTimeout(async () => {
          if (!WifiManager.isWifiConnected()) {
            ToastUtil.showToast('Wi-Fi 尚未完全连接');
            return;
          }

          if (!WifiManager.isCameraWifi()) {
            ToastUtil.showToast('当前不是相机 Wi-Fi');
            return;
          }

          await WifiManager.bindToCameraWifi();
          ToastUtil.showToast('相机连接成功');
        }, 2000);
      }
    );
  }, 1000);
}

页面生命周期:

aboutToAppear(): void {
  WifiManager.startListen();
}

aboutToDisappear(): void {
  WifiManager.stopListen();
}

访问云接口:

async function requestCloud(): Promise<void> {
  await WifiManager.withInternet(async () => {
    await requestCloudFileList();
  });
}

示例中的隐私信息统一使用占位符:

CAMERA_WIFI_SSID
CAMERA_WIFI_PASSWORD
CAMERA_GATEWAY
CLOUD_API_URL
USER_ID
DEVICE_SERIAL
posted @ 2026-09-01 17:43  带头大哥d小弟  阅读(13)  评论(0)    收藏  举报