鸿蒙元服务ASCF弱网监听与网络状态检测适配实践
为什么要在元服务里处理网络状态做元服务开发时,网络状态很容易被忽略,但它直接影响接口请求体验。用户在地铁里从 Wi-Fi 切到蜂窝,或信号变差进入弱网,如果没有处理,请求可能直接超时。ASCF 提供了 getNetworkType、getLocalIPAddress、onNetworkStatusChange、onNetworkWeakChange 等网络 API,可以覆盖网络类型获取、局域网 IP 获取、连接状态监听和弱网状态感知。
先分清 API 和权限
getNetworkType 用于获取当前网络类型;getLocalIPAddress 用于获取设备在局域网中的 IP 和子网掩码;onNetworkStatusChange 监听网络连接状态变化;onNetworkWeakChange 监听弱网状态变化。权限方面,getNetworkType 和 onNetworkStatusChange 需要 ohos.permission.GET_NETWORK_INFO,getLocalIPAddress 需要 ohos.permission.GET_WIFI_INFO,两者不要混用。
获取当前网络类型
最基础的用法是查询当前连接的是什么网络:
has.getNetworkType({
success: (res) => {
console.info('当前网络类型:', res.networkType);
},
fail: (err) => {
console.error('获取网络类型失败:', err);
}
});
networkType 返回字符串。需要注意,cellular 不会区分 4G 或 5G,它只表示当前使用的是移动数据,具体制式需要查其他 API。
获取局域网 IP 地址
getLocalIPAddress 可以拿到设备在局域网中的 IP 和子网掩码:
has.getLocalIPAddress({
success: (res) => {
console.info('局域网 IP:', res.localip);
console.info('子网掩码:', res.netmask);
},
fail: (err) => {
console.error('获取 IP 失败:', err);
}
});
这个接口需要 ohos.permission.GET_WIFI_INFO,而且只有在连接 Wi-Fi 时才能拿到有效值。蜂窝网络下没有局域网概念,接口可能返回空或直接失败。它更适合局域网设备发现或 P2P 通信,普通业务开发一般用不到。
监听网络连接状态变化
用户使用过程中切换网络很常见,因此需要监听网络状态。注册方式如下:
const onNetworkStatusChange = (res) => {
console.info('网络状态变化:', res);
console.info('是否连接:', res.isConnected);
console.info('网络类型:', res.networkType);
};
has.onNetworkStatusChange(onNetworkStatusChange);
回调返回两个关键字段:isConnected 表示当前是否有网络连接,networkType 表示当前网络类型,取值与 getNetworkType 一致。不再需要监听时要移除:
has.offNetworkStatusChange(onNetworkStatusChange);
这里有一个常见坑:offNetworkStatusChange 必须传入与注册时同一个函数对象。如果注册时使用匿名函数,移除时再写一个匿名函数,并不是同一个引用,监听就移除不掉。
// 错误写法:这样移除不掉
has.onNetworkStatusChange((res) => { /* ... */ });
has.offNetworkStatusChange((res) => { /* ... */ });
// 正确写法:用变量保存
const handler = (res) => { /* ... */ };
has.onNetworkStatusChange(handler);
has.offNetworkStatusChange(handler);
监听弱网状态变化
onNetworkWeakChange 是 1.0.12 新增的,用于检测弱网:
const onNetworkWeakChange = (res) => {
console.info('弱网状态变化:', res);
console.info('是否弱网:', res.weakNet);
console.info('网络类型:', res.networkType);
};
has.onNetworkWeakChange(onNetworkWeakChange);
返回字段包括 weakNet,表示当前是否处于弱网状态;networkType 表示当前网络类型,但这里只会出现 cellular 和 wifi 两种。移除方式与网络状态监听相同:
has.offNetworkWeakChange(onNetworkWeakChange);
弱网检测的实际意义比较大。进入弱网后,可以降低图片质量、减少请求频率,或者提示用户当前网络较差。相比让用户一直等转圈,这种降级和反馈体验更好。
在页面生命周期里管理监听
实际项目中,可以在页面生命周期里注册和移除监听,并结合 getNetworkType 获取初始状态。核心思路是把回调函数挂到 this 上,用下划线前缀区分,便于在页面销毁时精确移除:
Page({
data: {
networkType: '未知',
isConnected: true,
isWeakNet: false,
localIP: '',
},
onReady() {
this.getNetworkInfo();
},
onUnload() {
this.removeListeners();
},
getNetworkInfo() {
has.getNetworkType({
success: (res) => {
this.setData({ networkType: res.networkType });
}
});
this._onNetworkStatusChange = (res) => {
this.setData({
isConnected: res.isConnected,
networkType: res.networkType
});
if (!res.isConnected) {
console.warn('网络已断开');
}
};
has.onNetworkStatusChange(this._onNetworkStatusChange);
this._onNetworkWeakChange = (res) => {
this.setData({ isWeakNet: res.weakNet });
if (res.weakNet) {
console.warn('进入弱网状态');
}
};
has.onNetworkWeakChange(this._onNetworkWeakChange);
},
getLocalIP() {
has.getLocalIPAddress({
success: (res) => {
this.setData({ localIP: res.localip });
},
fail: (err) => {
console.error('获取 IP 失败:', err);
this.setData({ localIP: '获取失败' });
}
});
},
removeListeners() {
if (this._onNetworkStatusChange) {
has.offNetworkStatusChange(this._onNetworkStatusChange);
}
if (this._onNetworkWeakChange) {
has.offNetworkWeakChange(this._onNetworkWeakChange);
}
}
});
权限配置
在 module.json5 的 requestPermissions 中加入权限。若只使用 getNetworkType 和 onNetworkStatusChange,配置 ohos.permission.GET_NETWORK_INFO 即可;如果还要使用 getLocalIPAddress,再按需加入 ohos.permission.GET_WIFI_INFO。权限的 reason 和 usedScene 应按实际使用场景填写,避免声明无关权限。
几个容易踩的坑
弱网回调的 networkType 只有 cellular 和 wifi,不像 onNetworkStatusChange 那样种类多,因此不能通过弱网回调判断蓝牙等连接类型。offNetworkStatusChange 如果不传 callback 参数,会移除当前页面所有网络状态监听;如果页面里有多个监听函数,不传参调用会全部移除,线上代码应传具体函数引用。getLocalIPAddress 在蜂窝网络下返回空或失败,不要在移动数据环境下依赖它。networkType 在部分特殊网络环境,例如企业内网代理、特殊 VPN 配置下,可能返回 unknown;代码不能只处理 wifi 和 cellular,要对未知类型做兜底。
结合请求做弱网降级
只监听弱网还不够,业务层要响应。可以在请求封装里先判断网络状态:
function requestWithNetCheck(options) {
has.getNetworkType({
success: (res) => {
if (res.networkType === 'none') {
console.warn('无网络连接,跳过请求');
if (options.fail) {
options.fail({ errMsg: '无网络连接' });
}
return;
}
has.request({
url: options.url,
method: options.method || 'GET',
data: options.data,
success: options.success,
fail: options.fail
});
}
});
}
更进一步,可以在弱网状态下降低请求频率,例如把轮询间隔从 5 秒改成 30 秒,或取消非关键请求。这些逻辑不复杂,但对用户体验提升明显。
给用户可见的 UI 反馈
监听到网络变化后,除了业务降级,UI 也要给出反馈。例如在页面顶部显示网络状态提示条:
Page({
data: {
showNetTip: false,
netTipText: '',
netTipType: 'warn',
},
onReady() {
this._onNetworkStatusChange = (res) => {
if (!res.isConnected) {
this.setData({
showNetTip: true,
netTipText: '网络已断开,请检查网络连接',
netTipType: 'error'
});
} else {
this.setData({
showNetTip: true,
netTipText: '已恢复' + res.networkType + '网络',
netTipType: 'success'
});
setTimeout(() => {
this.setData({ showNetTip: false });
}, 3000);
}
};
has.onNetworkStatusChange(this._onNetworkStatusChange);
}
});
顶部提示条比直接弹 modal 框侵入性更小,不会打断用户操作。
多页面与全局监听
如果多个页面都需要监听网络状态,每个页面各自注册和移除即可。ASCF 的监听按页面隔离,页面销毁时会自动清理。若要做 App 级全局网络状态管理,可以在 app.js 的 onCreate 里注册全局监听,再通过事件总线或全局状态同步给各个页面:
App({
data: {
globalNetworkType: 'unknown',
globalIsConnected: true,
},
onCreate() {
has.onNetworkStatusChange((res) => {
this.data.globalNetworkType = res.networkType;
this.data.globalIsConnected = res.isConnected;
// 这里可以触发全局事件通知各页面
});
}
});
不过大多数场景按页面管理就够了,除非元服务对网络依赖特别重,否则不必把监听架构做得太复杂。
兼容与总结
onNetworkWeakChange 是 1.0.12 才加入的,如果需要兼容低版本 ASCF,记得做降级处理,不要直接调用导致报错。总体来说,网络状态感知看起来简单,但做好权限区分、监听引用管理、弱网降级和 UI 反馈,就能明显改善弱网和切换网络场景下的用户体验。
Re: 鸿蒙元服务ASCF弱网监听与网络状态检测适配实践
感谢分享,内容很实用。之前做元服务时确实容易只顾着接口请求,忽略网络状态变化,尤其是弱网场景,等到用户反馈一直转圈才去补。你提到的权限区分很关键,getNetworkType 和 onNetworkStatusChange 用 GET_NETWORK_INFO,getLocalIPAddress 用 GET_WIFI_INFO,这两个我之前也差点混着申请。offNetworkStatusChange 那个坑更深,匿名函数注册后再用匿名函数移除根本移不掉,页面销毁后回调还活着,容易出现 setData 到已销毁页面的问题,用 this 上挂变量、在 onUnload 里精确移除确实更稳。 弱网监听 onNetworkWeakChange 这一段也很有启发,进入弱网后做图片降级、减少请求频率、给用户明确提示,比一直等超时体验好很多。想请教一下,如果页面只是 onHide 而不是 onUnload,监听一般保留还是也移除?多个页面同时注册监听时,会不会有冲突或者重复回调的情况?整体总结得很到位,学到了。Re: 鸿蒙元服务ASCF弱网监听与网络状态检测适配实践
感谢分享,这篇把元服务里网络状态和弱网监听的几个关键点讲得很清楚。getNetworkType、getLocalIPAddress、onNetworkStatusChange、onNetworkWeakChange 的用途和权限区分很实用,特别是 GET_NETWORK_INFO 和 GET_WIFI_INFO 不能混用,以及 off 方法必须传注册时同一个函数对象这个坑,确实容易忽略。页面 onReady 注册、onUnload 移除并配合 getNetworkType 拿初始状态的写法也很顺,后面做弱网降级和用户提示就有依据了。想请教下,onNetworkWeakChange 在弱网恢复时会再回调一次把 weakNet 置回 false 吗?另外弱网监听里 networkType 只有 wifi 和 cellular,如果当前完全没连接,是不是就只靠 onNetworkStatusChange 的 isConnected 来判断?Re: 鸿蒙元服务ASCF弱网监听与网络状态检测适配实践
这篇整理挺实用的,尤其是把权限区分讲清楚了:getNetworkType 和 onNetworkStatusChange 用 GET_NETWORK_INFO,getLocalIPAddress 用 GET_WIFI_INFO,确实很容易混。还有 offNetworkStatusChange 必须传同一个函数对象这个坑,用变量保存回调这点很关键,匿名函数写法在实际项目里很容易导致监听移除不掉。 另外弱网监听 onNetworkWeakChange 这段也很有参考价值,进入弱网后做图片降级、降低请求频率或给用户提示,比一直转圈体验好很多。把监听注册和移除放到页面生命周期里管理,也符合元服务页面级资源释放的思路。 不过首帖末尾的页面示例好像没贴完,停在 isConnected 那里了。方便的话可以补一下 removeListeners 和弱网监听的完整写法,整体对做鸿蒙元服务网络适配帮助很大。
页:
[1]