网络状态监听:监听网络连接类型(WiFi/5G)变化(41)
在鸿蒙(HarmonyOS)开发中,实时监听网络状态是保障应用体验的核心能力。当用户在 Wi-Fi、4G、5G 等网络间切换时,应用需及时响应(如提示网络变化、调整下载并发数),避免因网络波动导致卡顿或流量浪费。
鸿蒙通过@kit.NetworkKit中的@ohos.net.connection模块提供标准化的网络状态监听接口。以下是完整的实战开发指南:
一、 环境准备与权限配置
网络状态监听属于敏感操作,必须在module.json5中声明相关权限:
"requestPermissions": [ { "name": "ohos.permission.INTERNET" }, { "name": "ohos.permission.GET_NETWORK_INFO" } ]二、 核心代码:网络状态监听与类型识别
通过createNetConnection创建网络连接对象,注册各类网络变化事件,并在回调中解析当前网络类型。
import { connection } from '@kit.NetworkKit'; import { BusinessError } from '@kit.BasicServicesKit'; @Entry @Component struct NetworkMonitorDemo { private netConnection: connection.NetConnection = connection.createNetConnection(); aboutToAppear() { this.startNetworkMonitor(); } private startNetworkMonitor() { // 1. 注册网络订阅(必须先注册,才能接收后续事件) this.netConnection.register((error: BusinessError) => { if (error) { console.error('网络注册监听失败:', JSON.stringify(error)); return; } console.info('网络注册监听成功'); }); // 2. 监听网络可用事件 this.netConnection.on('netAvailable', (data: connection.NetHandle) => { console.info(`网络可用, netId: ${data.netId}`); }); // 3. 监听网络能力变化(核心:用于识别网络类型切换) this.netConnection.on('netCapabilitiesChange', (data: connection.NetCapabilityInfo) => { const bearerTypes = data.netCap?.bearerTypes; const networkCaps = data.netCap?.networkCap; // 解析网络类型(Wi-Fi / 蜂窝网络) if (bearerTypes?.includes(connection.NetBearType.BEARER_WIFI)) { console.info('当前网络类型: Wi-Fi'); } else if (bearerTypes?.includes(connection.NetBearType.BEARER_CELLULAR)) { console.info('当前网络类型: 蜂窝网络 (4G/5G)'); } // 解析网络能力(如是否真正可访问互联网) if (networkCaps?.includes(connection.NetCap.NET_CAPABILITY_VALIDATED)) { console.info('网络已验证,可正常访问互联网'); } }); // 4. 监听网络丢失事件(如断开 Wi-Fi 且无蜂窝网络) this.netConnection.on('netLost', (data: connection.NetHandle) => { console.warn(`网络丢失, netId: ${data.netId}`); }); // 5. 监听网络不可用事件(如连上了 Wi-Fi 但无法上网) this.netConnection.on('netUnavailable', () => { console.warn('当前网络不可用'); }); } aboutToDisappear() { // 退出页面时取消订阅,防止内存泄漏 this.netConnection.unregister((error: BusinessError) => { if (error) { console.error('取消网络监听失败:', JSON.stringify(error)); } }); } build() { Column({ space: 20 }) { Text('网络状态监听演示') .fontSize(24) .fontWeight(FontWeight.Bold) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } }三、 进阶:结合状态管理实现 UI 联动
在实际业务中,网络状态通常需要全局共享并驱动 UI 更新。推荐使用AppStorage结合@StorageProp和@Watch实现响应式联动。
// 1. 在工具类或全局监听中,将状态写入 AppStorage this.netConnection.on('netCapabilitiesChange', (data) => { let isNetAvailable = data.netCap?.networkCap?.includes(connection.NetCap.NET_CAPABILITY_VALIDATED); AppStorage.setOrCreate('isNetAvailable', isNetAvailable ?? false); }); // 2. 在 UI 组件中监听状态变化 @StorageProp('isNetAvailable') @Watch('onNetworkChanged') isNetAvailable: boolean = true; onNetworkChanged() { if (this.isNetAvailable) { console.info('网络已恢复,执行重新连接/恢复下载逻辑'); } else { console.warn('网络已断开,暂停下载并提示用户'); } }开发建议与注意事项
- 区分
netLost与netUnavailable:netLost:网络严重中断或正常断开(如手动关闭 Wi-Fi)。netUnavailable:网络已连接但不可用(如连上了 Wi-Fi 但路由器未连外网,图标显示感叹号)。
- 网络切换的事件触发顺序:当设备从 Wi-Fi 切换到蜂窝网络时,系统会先触发
netLost(Wi-Fi 丢失),再触发netAvailable(蜂窝网络可用)。在开发重连逻辑时需注意时序。 - 低功耗设计:鸿蒙网络监听采用事件订阅机制,仅在状态变化时唤醒应用回调,避免了持续轮询带来的高耗电问题。
- 不支持主动切换:系统原生能力仅支持通过回调“感知”网络切换,不支持应用主动进行网络切换。
四、 精准识别蜂窝网络代际(5G/4G/3G/2G)
基础的connection模块只能区分出当前是否处于“蜂窝网络”状态。如果需要精准识别当前是 5G、4G 还是 3G,需要结合@ohos.telephony.radio模块获取信号信息。
核心代码示例:
import { connection } from '@kit.NetworkKit'; import { radio } from '@kit.TelephonyKit'; // 当监听到当前网络为蜂窝网络时,进一步获取具体代际 async function getCellularGeneration() { try { // 获取当前设备的信号信息列表(支持双卡) const signalInfos = await radio.getSignalInformation(); if (signalInfos && signalInfos.length > 0) { // 获取主卡的信号类型 const signalType = signalInfos[0].signalType; switch (signalType) { case radio.NetworkType.NETWORK_TYPE_NR: console.info('当前蜂窝网络: 5G'); break; case radio.NetworkType.NETWORK_TYPE_LTE: console.info('当前蜂窝网络: 4G'); break; case radio.NetworkType.NETWORK_TYPE_WCDMA: case radio.NetworkType.NETWORK_TYPE_TDSCDMA: console.info('当前蜂窝网络: 3G'); break; default: console.info('当前蜂窝网络: 2G/未知'); break; } } } catch (err) { console.error('获取蜂窝网络代际失败'); } }五、 弱网状态感知(ASCF 框架)
在音视频通话、实时游戏等对网络延迟敏感的场景中,仅知道“网络是否连接”是不够的,还需要感知当前是否处于“弱网”状态。鸿蒙 ASCF 框架提供了专门的弱网监听接口。
核心代码示例:
import { has } from '@kit.ASCFKit'; // 假设基于 ASCF 框架 // 监听弱网状态变化 has.onNetworkWeakChange((res) => { console.info(`弱网状态变更: ${res.weakNet}, 当前网络类型: ${res.networkType}`); if (res.weakNet) { // 弱网策略:降低视频码率、减少心跳频率、暂停后台预加载等 console.warn('检测到弱网,正在切换至低画质模式...'); } else { // 网络恢复:恢复正常策略 console.info('网络状况良好,恢复标准画质'); } }); // 在生命周期中取消监听 has.offNetworkWeakChange();六、 多网并发与连接迁移(Network Boost Kit)
对于大型文件下载、直播推流等高吞吐业务,鸿蒙提供了 Network Boost Kit,允许应用感知多网并发状态(例如同时使用 Wi-Fi 和蜂窝网络),从而制定更优的数据传输策略。
核心代码示例:
import { netHandover } from '@kit.NetworkBoostKit'; import { BusinessError } from '@kit.BasicServicesKit'; // 订阅多网状态信息变化 try { netHandover.on('multiPathStateChange', (data: netHandover.MultiPathStateInfo) => { console.info("多网状态变化: " + JSON.stringify(data)); // 根据多网状态调整并发下载线程数或传输策略 }); } catch (err) { console.error('监听多网状态失败: ' + (err as BusinessError).message); } // 业务结束时取消订阅 try { netHandover.off('multiPathStateChange'); } catch (err) { console.error('取消多网状态监听失败: ' + (err as BusinessError).message); }七、 网络质量量化监控(延迟、带宽、信号强度)
在音视频通话、实时游戏等对网络延迟极度敏感的场景中,除了感知“弱网”,还需要获取具体的网络质量指标(如 RTT 延迟、上下行带宽、信号强度 RSRP)。由于系统可能没有直接提供实时的质量变化监听,通常采用定时主动探测的方式来实现。
核心代码示例:
import { connection } from '@kit.NetConnectionKit'; // 定义网络质量模型 interface NetworkQuality { level: 'EXCELLENT' | 'GOOD' | 'FAIR' | 'POOR' | 'UNKNOWN'; signalStrength: number; latency: number; bandwidth: number; } // 定时检测网络质量 async function measureNetworkQuality(): Promise<NetworkQuality> { const startTime = Date.now(); try { // 通过发起轻量级请求来测量延迟(RTT) await fetch('https://connectivitycheck.gstatic.com/generate_204', { timeout: 5000 }); const latency = Date.now() - startTime; // 根据延迟评估质量等级 let level: NetworkQuality['level'] = 'UNKNOWN'; if (latency < 100) level = 'EXCELLENT'; else if (latency < 300) level = 'GOOD'; else if (latency < 800) level = 'FAIR'; else level = 'POOR'; return { level, signalStrength: 0, latency, bandwidth: 0 }; } catch (err) { return { level: 'POOR', signalStrength: 0, latency: -1, bandwidth: 0 }; } } // 每 5 秒执行一次质量评估 setInterval(async () => { const quality = await measureNetworkQuality(); console.info(`当前网络质量: ${quality.level}, 延迟: ${quality.latency}ms`); }, 5000);八、 智能 DNS 解析
在多网络并存或复杂网络环境下,直接使用域名发起请求可能会遇到 DNS 劫持或解析缓慢的问题。鸿蒙提供了系统级的智能 DNS 解析接口,可以直接获取目标域名的 IP 地址列表,便于应用层自行管理连接。
核心代码示例:
import { connection } from '@kit.NetworkKit'; async function resolveDomain() { try { const addresses = await connection.getAddressesByName("www.example.com"); console.info("解析到的 IP 地址列表:", addresses.join(', ')); // 业务层可使用解析出的 IP 直接建立连接,绕过系统默认 DNS } catch (err) { console.error("DNS 解析失败:", (err as BusinessError).message); } }九、 底层网络状态强制修正
在某些极端场景下(如底层网卡驱动异常、代理软件干扰),应用内部记录的网络状态可能与系统网络管理器不一致。鸿蒙提供了强制报告网络状态的接口,用于纠正系统的误判。
核心代码示例:
import { connection } from '@kit.NetworkKit'; // 当发现网络状态异常且确认当前网络不可用时,强制向系统报告网络断开 function forceReportDisconnect(badNetHandle: connection.NetHandle) { connection.reportNetDisconnected(badNetHandle); console.warn('已强制报告网络断开'); } // 当确认某个网络句柄实际可用,但系统未识别时,强制报告连接 function forceReportConnect(goodNetHandle: connection.NetHandle) { connection.reportNetConnected(goodNetHandle); console.info('已强制报告网络连接'); }底层通信资源管控与避坑
在复杂的网络切换过程中,底层通信资源的管理至关重要,处理不当极易导致内存泄漏或请求异常。
- Socket 资源强制释放:当监听到网络切换(如 Wi-Fi 切 5G)或网络丢失时,必须主动关闭旧的 Socket 连接。旧的网络句柄在新的网络环境下已失效,继续持有会导致资源泄漏。
- 推荐使用高级通信套件:在多网络频繁切换的场景下,强烈建议使用
@kit.RemoteCommunicationKit替代原生的 HTTP 模块,它内置了更好的连接池管理和网络异常恢复机制。 - 紧急情况下的状态修正:当遇到应用内部记录的网络状态与系统管理器不一致时(例如应用认为已断网,但系统实际可用),可以调用
connection.reportNetDisconnected(badNetHandle)或connection.reportNetConnected(goodNetHandle)强制向系统报告网络状态。 - 生命周期严格绑定:网络监听会持续占用系统资源。务必在
EntryAbility的onCreate中开启订阅,在onWindowStageDestroy中关闭订阅,防止应用进入后台后仍进行不必要的状态回调。
