鸿蒙NEXT开发实战往期必看文章:
一分钟了解”纯血版!鸿蒙HarmonyOS Next应用开发!
“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)
HarmonyOS NEXT应用开发案例实践总结合(持续更新......)
HarmonyOS NEXT应用开发性能优化实践总结(持续更新......)
概述
本文章主要介绍了网络管理中网络连接管理、网络信息查询和网络状态监听等。
- 网络连接管理主要包括蜂窝网络和Wi-Fi网络的连接管理,用户可以自行选择使用蜂窝网络或是使用Wi-Fi网络。
- 网络信息查询主要针对蜂窝网络和Wi-Fi网络的相关信息查询。
- 网络状态监听主要包含判断当前环境下网络是否可用以及是否处于弱网环境等情况。
在需要使用网络时,通常有两种选择:蜂窝网络或Wi-Fi网络。当成功连接蜂窝网络或Wi-Fi网络后,若应用需要区分当前连接的具体网络类型,可通过网络连接管理功能进行查询。当使用场景发生变化时,需要对网络状态进行监听,如查询当前网络是否可用、判断网络质量的优劣等,并据此做出切换网络或提示用户等操作,从而提升用户体验。
本文章是为了帮助开发者了解网络管理中常用的查询方式:
- 获取当前网络连接类型
- 判断当前网络是否可用
- 查询网络路由信息、网络链路信息
- 获取网络状态,包括蜂窝和Wi-Fi等网络状态
- 查询蜂窝和Wi-Fi使用相关的信息
帮助开发者了解如何进行网络状态变化的监听:
- 监听网络可用与丢失
- 监听弱网环境
网络管理
查询网络连接信息
获取当前网络连接类型
当需要判断当前使用的网络是蜂窝或者Wi-Fi时,可以通过以下步骤实现:
- 导入模块。
import { connection } from '@kit.NetworkKit'; import { BusinessError } from '@kit.BasicServicesKit';
- 使用getDefaultNetSync先获取默认激活的数据网络。
- 调用getNetCapabilitiesSync去获取网络的类型、拥有的能力等信息。
- 根据返回结果中的bearerTypes判断,为BEARER_CELLULAR时(值为0),表示蜂窝网络;为BEARER_WIFI时(值为1),表示Wi-Fi网络;为BEARER_BLUETOOTH时(值为2),表示蓝牙网络;为BEARER_ETHERNET时(值为3),表示以太网网络;为BEARER_VPN时(值为4),表示VPN网络。
核心代码
getNetworkConnectionType() {
try {
let netHandle = connection.getDefaultNetSync();
if (!netHandle || netHandle.netId === 0) {
return;
}
let netCapability = connection.getNetCapabilitiesSync(netHandle);
console.log('bearerTypes:', JSON.stringify(netCapability.bearerTypes));
} catch (e) {
let err = e as BusinessError;
console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
判断当前网络是否可用
使用网络前,例如打开一个应用时,需要检查当前连接的网络是否可用。如果可用,则正常进行网络请求;如果不可用,则需要提示用户网络不可用。判断当前连接的网络是否可用,可以通过以下步骤实现:
- 进行“获取当前网络连接类型”中的步骤1、2、3。
- 根据返回结果,判断networkCap数组中的值是否存在与NET_CAPABILITY_VALIDATED相等的值。如果有,则表示网络可用。
核心代码
judgeHasNet(): boolean {
try {
let netHandle = connection.getDefaultNetSync();
if (!netHandle || netHandle.netId === 0) {
return false;
}
let netCapability = connection.getNetCapabilitiesSync(netHandle);
let cap = netCapability.networkCap || [];
if (cap.includes(connection.NetCap.NET_CAPABILITY_VALIDATED)) {
//connection.NetCap.NET_CAPABILITY_VALIDATED,该值代表网络是通的,能够发起HTTP和HTTPS的请求。
// 网络信息变化,网络可用
return true;
} else {
// 网络信息变化,网络不可用
return false;
}
} catch (e) {
let err = e as BusinessError;
console.error("JudgeHasNet" + JSON.stringify(err));
}
return false;
}
查询网络路由信息、网络链路信息
当需要进行网络故障诊断、网络性能优化、考虑网络安全需求时,需要查询网络路由信息、网络链路信息等,可以通过以下步骤实现:
- 进行“获取当前网络连接类型”中的步骤1。
- 使用getDefaultNet先获取默认激活的数据网络。
- 调用getConnectionProperties获取netHandle对应的网络的连接信息。
- 返回结果ConnectionProperties中,即包含网络路由信息RouteInfo、网络链路信息LinkAddress等。
核心代码
getRouteInfoAndLinkAddress() {
connection.getDefaultNet().then((netHandle: connection.NetHandle) => {
if (!netHandle || netHandle.netId === 0) {
// 当前无默认网络时,获取的netHandler的netid为0,属于异常场景,此处可以实际情况自行添加一些处理机制。
return;
}
connection.getConnectionProperties(netHandle, (error: BusinessError, data: connection.ConnectionProperties) => {
if (error) {
console.error(`Failed to get connection properties. Code:${error.code}, message:${error.message}`);
return;
}
console.info("Succeeded to get data: " + JSON.stringify(data));
let routeInfo = data.routes;
let linkAddress = data.linkAddresses;
console.info("routeInfo is: " + JSON.stringify(routeInfo));
console.info("linkAddress is: " + JSON.stringify(linkAddress));
})
});
}
查询当前网络信息
蜂窝网络查询
下面将介绍蜂窝网络的相关查询,主要包括获取网络状态、查询当前网络是3G/4G/5G和判断主卡的Radio是否打开等。
获取网络状态
当需要查询手机卡注册网络的运营商名称、是否处于漫游状态、设备的网络注册状态等信息时,可以通过以下步骤实现:
- 导入模块。
import { radio } from '@kit.TelephonyKit'; import { BusinessError } from '@kit.BasicServicesKit';
- 使用getNetworkState获取网络状态。
- 返回结果NetworkState中,包含当前网络状态等信息,其中regState字段表示设备的网络注册状态。
核心代码
getNetworkStatus(){
radio.getNetworkState((err: BusinessError, data: radio.NetworkState) => {
if (err) {
console.error(`getNetworkState failed, callback: err->${JSON.stringify(err)}`);
return;
}
console.log(`getNetworkState success, callback: data->${JSON.stringify(data)}`);
});
}
查询当前网络是3G/4G/5G
视频播放应用在5G网络下可以默认加载超高清视频,以充分利用高速带宽;在4G网络下加载高清视频;而在3G网络下,为了避免卡顿,可能只加载标清视频。如何控制加载对应清晰度的视频,就需要查询当前网络是3G/4G/5G,可以通过以下步骤实现:
- 进行“获取网络状态”中的步骤1。
- 使用getSignalInformation获取指定SIM卡槽对应的注册网络信号强度信息列表。
- 返回结果signalinformation中,signalType代表网络类型NetworkType。
signalType的值对应网络类型如下:
值 | 网络类型 |
---|---|
GSM | 2G |
CDMA | 2G |
WCDMA | 3G |
TDSCDMA | 3G |
LTE | 4G |
NR | 5G |
核心代码
getSignalType(){
let slotId: number = 0;
radio.getSignalInformation(slotId, (err: BusinessError, data: Array<radio.SignalInformation>) => {
if (err) {
console.error(`getSignalInformation failed, callback: err->${JSON.stringify(err)}`);
return;
}
console.log(`getSignalInformation success, callback: data->${JSON.stringify(data)}`);
let signalType = data[0].signalType;
console.log(`signalType is: ${signalType}`);
});
}
判断主卡的Radio是否打开
当用户在国外或者其他运营商的网络覆盖区域时,主卡Radio打开可能会导致手机自动连接到其他网络并产生漫游费用。因此,判断主卡Radio的状态可以让用户提前做好防范措施。判断主卡的Radio是否打开,可以通过以下步骤实现:
核心代码
getRadioStatus(){
radio.isRadioOn((err: BusinessError, data: boolean) => {
if (err) {
console.error(`isRadioOn failed, callback: err->${JSON.stringify(err)}`);
return;
}
console.log(`isRadioOn success, callback: data->${JSON.stringify(data)}`);
});
}
Wi-Fi查询
下面将介绍Wi-Fi网络的相关查询,主要包括查询WLAN是否已使能、查询WLAN是否已连接、获取扫描到的热点列表、获取当前连接Wi-Fi的信号强度和添加候选网络配置等。
查询WLAN是否已使能
查询WLAN是否已使能,可以帮助用户快速了解自己是否可以使用Wi-Fi网络进行连接。并且当Wi-Fi跟蜂窝同时存在时,有助于实现网络连接的无缝切换。查询WLAN是否已使能,可以通过以下步骤实现:
- 导入模块。
import { wifiManager } from '@kit.ConnectivityKit';
- 使用isWifiActive查询WLAN是否已使能。
- 如果返回结果为true,则表示WLAN已使能。否则,表示未使能。
核心代码
getWifiStatus() {
try {
let isWifiActive = wifiManager.isWifiActive();
console.info("isWifiActive:" + isWifiActive);
} catch (error) {
console.error("failed:" + JSON.stringify(error));
}
}
查询WLAN是否已连接
查询WLAN是否已连接是判断能否通过Wi-Fi 进行各种网络活动的直接方式。只有在 WLAN 连接成功后,用户才能利用 Wi-Fi网络的带宽优势进行诸如高清视频播放、大文件下载、在线游戏等对网络带宽和稳定性要求较高的操作。查询WLAN是否已连接,可以通过以下步骤实现:
核心代码
getWifiIsConnected() {
try {
let ret = wifiManager.isConnected();
console.info("isConnected:" + ret);
} catch (error) {
console.error("failed:" + JSON.stringify(error));
}
}
获取扫描到的热点列表
当用户想连接热点时,就需要通过获取扫描到的热点列表来查找对应热点。获取扫描到的热点列表,可以通过以下步骤实现:
核心代码
getScanInfoList() {
try {
let scanInfoList = wifiManager.getScanInfoList();
console.info("scanInfoList:" + JSON.stringify(scanInfoList));
} catch (error) {
console.error("failed:" + JSON.stringify(error));
}
}
获取当前连接Wi-Fi的信号强度
在下载大文件或观看高清视频时,如果Wi-Fi信号强度不足,可能会导致下载速度缓慢、视频卡顿等问题。通过获取信号强度,用户可以初步判断当前网络是否能够满足其对速度的需求。获取当前连接Wi-Fi的信号强度,可以通过以下步骤实现:
核心代码
getSignalLevel() {
try {
let rssi = 0;
let band = 0;
let level = wifiManager.getSignalLevel(rssi, band);
console.info("level:" + JSON.stringify(level));
} catch (error) {
console.error("failed:" + JSON.stringify(error));
}
}
添加候选网络配置
添加候选网络配置可以让设备在当前连接的网络出现问题(如信号丢失、网络故障等)或者用户离开当前网络覆盖范围时,自动尝试连接其他预先配置的候选网络。添加候选网络配置,可以通过以下步骤实现:
核心代码
addCandidateConfig() {
try {
let config: wifiManager.WifiDeviceConfig = {
ssid: "****",
preSharedKey: "****",
securityType: 0
}
wifiManager.addCandidateConfig(config).then(result => {
console.info("result:" + JSON.stringify(result));
}).catch((err: number) => {
console.error("failed:" + JSON.stringify(err));
});
} catch (error) {
console.error("failed:" + JSON.stringify(error));
}
}
网络状态监听
监听网络可用与丢失
在日常使用网络中,当使用Wi-Fi或者蜂窝时,如果信号良好,且手机、电脑、平板等可以顺利连接到网络,并进行在线视频播放、浏览网页、下载文件等操作,这些就是网络可用的典型场景。
而设备故障、信号干扰、网络拥堵、网络服务提供商的服务器故障、维护或升级都可能会导致网络丢失。为了提升用户上网体验,就需要对网络是否可用、网络是否丢失等进行监听,然后做出相应的处理。
网络连接管理中提供了对网络状态监听的方法,开发时定义了相关的监听方法后,在不同场景下会触发不同的事件,如:
- on('netAvailable'):订阅网络可用事件,当网络可用时触发该事件。
- on('netBlockStatusChange'):订阅网络阻塞状态事件,当网络阻塞时,如网络性能下降、数据传输出现延迟等情况时,会触发该事件。
- on('netCapabilitiesChange'):订阅网络能力变化事件,当网络能力变化时,如网络从无网络到有网络、从4G切换到5G时,会触发该事件。
- on('netConnectionPropertiesChange'):订阅网络连接信息变化事件,当网络连接信息变化时,如从无网络到有网络、从Wi-Fi切换到蜂窝时,会触发该事件。
- on('netLost'):订阅网络丢失事件,当网络严重中断或正常断开时触发该事件。
- on('netUnavailable'):订阅网络不可用事件,当网络不可用时触发该事件。
网络丢失和网络不可用并非是一个概念,网络丢失和网络不可用的区别如下:
- 网络丢失是指网络严重中断或正常断开事件,当断开Wi-Fi时,是属于正常断开网络连接,会触发netLost事件。
- 网络不可用是指网络不可用事件,当连接的网络不能使用时,会触发netUnavailable事件。
在播放视频时,可能会遇到无网络的情况,此时需要监听网络是否可用或者丢失,来实现对视频无网络时暂停、有网络时自动播放的能力,提升用户播放视频时的体验。通过注册监听网络相关变化,注册监听步骤如下:
- 进行“获取当前网络连接类型”中的步骤1。
- 调用connection.createNetConnection()方法,创建一个网络连接对象。
- 订阅指定网络状态变化的通知register(),只有先通过register接口注册了订阅事件,其他事件被触发时才能接收到对应的通知。
- 订阅网络可用事件 on('netAvailable')。
- 订阅网络丢失事件 on('netLost')。
- 订阅网络不可用事件 on('netUnavailable')。
- 退出页面或应用时取消订阅指定网络状态变化的通知unregister()。
核心代码
networkListen() {
this.netCon = connection.createNetConnection();
this.netCon.register((error: BusinessError) => {
if (error) {
console.log('networkListen fail' + JSON.stringify(error))
return;
}
});
this.netCon.on('netAvailable', (data: connection.NetHandle) => {
console.info("Succeeded to get netAvailable: " + JSON.stringify(data));
if (connection.hasDefaultNetSync()) {
if (this.networkPause) {
this.controller?.start();
this.networkPause = false;
}
}
});
// 订阅网络丢失事件
this.netCon.on('netLost', (data: connection.NetHandle) => {
if (connection.getAllNetsSync().length == 0) {
this.controller?.pause();
this.networkPause = true;
}
console.info("Succeeded to get netLost: " + JSON.stringify(data));
});
this.netCon.on('netCapabilitiesChange', (data: connection.NetCapabilityInfo) => {
console.info("Succeeded to get netCapabilitiesChange: " + JSON.stringify(data));
});
this.netCon.on('netUnavailable', () => {
console.info("Succeeded to get unavailable net event");
});
}
aboutToDisappear(): void {
this.netCon?.unregister((error: BusinessError) => {
console.log(JSON.stringify(error));
});
}
说明
connection.createNetConnection()方法中有两个可选传入参,netSpecifier和timeout。其中netSpecifier指定关注的网络的各项特征;timeout是超时时间(单位是毫秒);netSpecifier是timeout的必要条件,两者都没有则表示关注默认网络。
播放视频可使用Video组件实现,如果开发者想自定义视频播放,请参考视频播放。
@Component
export struct VideoPlayer{
private controller:VideoController | undefined;
@State videoSrc: string= 'https://www.example.com/example.mp4' // 使用时请替换为实际视频加载网址
build(){
Column() {
Video({
src: this.videoSrc,
controller: this.controller
})
}
}
}
当网络不可用时,调用暂停方法,暂停视频播放。
this.controller?.pause();
有网络后,调用播放方法,开始视频播放。
this.controller?.start();
上述过程中可能会涉及到Wi-Fi切换,当需要判断Wi-Fi是否切换,需要监听WLAN状态改变事件和WLAN连接状态改变事件,步骤如下:
- 进行“获取当前网络连接类型”中的步骤1和“查询WLAN是否已使能”中的步骤1。
- 调用connectionconnection.createNetConnection()方法,创建一个网络连接对象,并指定关注Wi-Fi网络的各项特征。
- 注册WLAN状态改变事件on('wifiStateChange')。
- 注册WLAN连接状态改变事件on('wifiConnectionChange')。
核心代码
wifiChangeListen() {
this.netCon = connection.createNetConnection({
netCapabilities: {
bearerTypes: [connection.NetBearType.BEARER_WIFI]
}
});
// 先使用register接口注册订阅事件
this.netCon.register((error: BusinessError) => {
console.log(JSON.stringify(error));
});
// 订阅网络可用事件。调用register后,才能接收到此事件通知
this.netCon.on('netAvailable', (data: connection.NetHandle) => {
console.info("WifiChangeListen-- Succeeded to get data: " + JSON.stringify(data));
});
// 订阅网络丢失事件。调用register后,才能接收到此事件通知
this.netCon.on('netLost', (data: connection.NetHandle) => {
console.info("WifiChangeListen-- Succeeded to get data: " + JSON.stringify(data));
});
let recvPowerNotifyFunc = (result: number) => {
console.info("WifiChangeListen-- Receive power state change event: " + result);
}
let recvWifiConnectionChangeFunc = (result: number) => {
console.info("WifiChangeListen-- Receive wifi connection change event: " + result);
}
// 注册事件
wifiManager.on("wifiStateChange", recvPowerNotifyFunc);
wifiManager.on("wifiConnectionChange", recvWifiConnectionChangeFunc);
}
其中状态改变事件的枚举:
枚举值 | 说明 |
---|---|
0 | 未激活。 |
1 | 已激活。 |
2 | 激活中。 |
3 | 去激活中。 |
连接状态改变事件的枚举:
枚举值 | 说明 |
---|---|
0 | 已断开。 |
1 | 已连接。 |
说明
设备从无网络到有网络会触发netAvailable事件、netCapabilitiesChange事件和netConnectionPropertiesChange事件;
设备从有网络到无网络状态会触发netLost事件;
设备从Wi-Fi切换到蜂窝会先触发netLost事件(Wi-Fi丢失),之后触发 netAvailable事件(蜂窝可用)。
弱网下网络切换
在播放视频时,可能会遇到弱网的环境,如乘坐高铁时、人员密集的场所等。这个时候需要监听网络状态以及网络质量,来实现提示用户进行网络切换或者对视频的清晰度做出相应调整,如:
1)在Wi-Fi弱信号的情况下,默认网络可能会切换到蜂窝网络。
2)在蜂窝网络弱信号的情况下,默认网络会优先切换到WiFi。
3)在网络质量低的环境下,自动降低并切换视频的清晰度。
判断是否是弱网环境的步骤如下:
- 导入模块。
import { BusinessError } from '@kit.BasicServicesKit'; import { netQuality } from '@kit.NetworkBoostKit';
- 订阅网络场景信息on( 'netSceneChange')。
- 根据网络场景状态变更回调信息中的Scene判断是否当前处于弱网环境。
- 如果处于弱网环境,提示用户切换网络。
核心代码
sceneChangeListen() {
try {
netQuality.on('netSceneChange', (list: Array<netQuality.NetworkScene>) => {
if (list.length > 0) {
list.forEach((networkScene) => {
// 回调信息处理
console.info(`Succeeded receive netSceneChange info`);
if (networkScene.scene == 'weakSignal' || networkScene.scene == 'congestion') {
// 表示为弱网场景
console.info(`The current network is weak`);
this.networkWeak();
}
});
}
});
} catch (err) {
console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
networkWeak() {
promptAction.showToast({
message: '当前处于弱网环境,建议您切换网络',
duration: 2000
});
}
判断是否为弱网可以通过下面3种方式:
- 监听系统实时判决:根据网络场景识别信息,如NetworkScene的取值为weakSignal/congestion时,系统直接判决为弱网。
if (networkScene.scene == 'weakSignal' || networkScene.scene == 'congestion' ) { // 表示为弱网场景 }
- 监听系统预测判决:根据网络场景识别中的弱信号预测信息,如NetworkScene系统预测即将进入弱网区域。
if (networkScene.weakSignalPrediction) { // 弱信号预测处理 }
- 应用自定义判决:
根据网络质量评估信息,如NetworkQos(linkUpBandwidth/linkDownBandwidth/rttMs/linkUpBufferDelayMs/linkUpBufferCongestionPercent),应用自定义门限来判决为弱网。
在弱网环境下,可以使用网络连接迁移能力,在通过系统发起多网迁移(WiFi<->蜂窝,主卡<->副卡等)的过程中,给应用提供连接迁移开始和完成通知,应用可根据连接迁移通知的建议进行重建,给用户带来平滑、高速、低时延的上网体验。
- 导入模块。
import { BusinessError } from '@kit.BasicServicesKit'; import { netHandover } from '@kit.NetworkBoostKit';
- 订阅连接迁移信息on( 'handoverChange')。
- 在连接迁移开始回调、连接迁移完成回调中自定义逻辑代码,处理相关业务。
核心代码
handoverChangeListen(){
try {
netHandover.on('handoverChange', (info: netHandover.HandoverInfo) => {
if (info.handoverStart) {
// 连接迁移开始回调,应用按照HandoverStart的建议调整数传策略
console.info('handover start');
} else if (info.handoverComplete) {
// 连接迁移完成回调,应用按照HandoverComplete的建议进行调速和重建恢复
console.info('handover complete');
}
});
} catch (err) {
console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
视频播放时,还可以通过判断当前网络质量来对视频的清晰度进行调整。若网络质量低,则切换视频到较低的清晰度。
- 导入模块。
import { BusinessError } from '@kit.BasicServicesKit'; import { netQuality } from '@kit.NetworkBoostKit';
- 订阅网络质量信息on( 'netQosChange')。
- 根据网络质量回调信息NetworkQos中的结果,如通过数据传输的链路类型、上下行实时带宽信息、上下行实时速率、RTT时延等信息自定义门限来区分网络质量高低。
- 根据网络质量高低的结果,进行视频清晰度切换。
核心代码
netQualityListen() {
try {
netQuality.on('netQosChange', (list: Array<netQuality.NetworkQos>) => {
if (list.length > 0) {
list.forEach((qos) => {
// 回调信息处理
console.info(`Succeeded receive netQosChange info`);
let lowNetQuality: boolean = false;
// 根据网络质量的相关信息,判断当前网络质量的高低。此处逻辑需要自定义实现,如果是低质量,则lowNetQuality为true。
// 如果网络质量低,则切换视频清晰度。
if(lowNetQuality){
this.toggleLowDefinition();
}
});
}
});
} catch (err) {
console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
toggleLowDefinition(){
this.innerResource = 'https://www.example.com/example_low_definition.mp4';
}