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 管理类不会直接依赖云模块,base 和 mine_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
浙公网安备 33010602011771号