查看: 242|回复: 0

鸿蒙元服务ASCF弱网监听与网络状态检测适配实践

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
为什么要在元服务里处理网络状态

做元服务开发时,网络状态很容易被忽略,但它直接影响接口请求体验。用户在地铁里从 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,两者不要混用。

获取当前网络类型

最基础的用法是查询当前连接的是什么网络:
  1. has.getNetworkType({
  2.   success: (res) => {
  3.     console.info('当前网络类型:', res.networkType);
  4.   },
  5.   fail: (err) => {
  6.     console.error('获取网络类型失败:', err);
  7.   }
  8. });
复制代码

networkType 返回字符串。需要注意,cellular 不会区分 4G 或 5G,它只表示当前使用的是移动数据,具体制式需要查其他 API。

获取局域网 IP 地址

getLocalIPAddress 可以拿到设备在局域网中的 IP 和子网掩码:
  1. has.getLocalIPAddress({
  2.   success: (res) => {
  3.     console.info('局域网 IP:', res.localip);
  4.     console.info('子网掩码:', res.netmask);
  5.   },
  6.   fail: (err) => {
  7.     console.error('获取 IP 失败:', err);
  8.   }
  9. });
复制代码

这个接口需要 ohos.permission.GET_WIFI_INFO,而且只有在连接 Wi-Fi 时才能拿到有效值。蜂窝网络下没有局域网概念,接口可能返回空或直接失败。它更适合局域网设备发现或 P2P 通信,普通业务开发一般用不到。

监听网络连接状态变化

用户使用过程中切换网络很常见,因此需要监听网络状态。注册方式如下:
  1. const onNetworkStatusChange = (res) => {
  2.   console.info('网络状态变化:', res);
  3.   console.info('是否连接:', res.isConnected);
  4.   console.info('网络类型:', res.networkType);
  5. };
  6. has.onNetworkStatusChange(onNetworkStatusChange);
复制代码

回调返回两个关键字段:isConnected 表示当前是否有网络连接,networkType 表示当前网络类型,取值与 getNetworkType 一致。不再需要监听时要移除:
  1. has.offNetworkStatusChange(onNetworkStatusChange);
复制代码

这里有一个常见坑:offNetworkStatusChange 必须传入与注册时同一个函数对象。如果注册时使用匿名函数,移除时再写一个匿名函数,并不是同一个引用,监听就移除不掉。
  1. // 错误写法:这样移除不掉
  2. has.onNetworkStatusChange((res) => { /* ... */ });
  3. has.offNetworkStatusChange((res) => { /* ... */ });
  4. // 正确写法:用变量保存
  5. const handler = (res) => { /* ... */ };
  6. has.onNetworkStatusChange(handler);
  7. has.offNetworkStatusChange(handler);
复制代码

监听弱网状态变化

onNetworkWeakChange 是 1.0.12 新增的,用于检测弱网:
  1. const onNetworkWeakChange = (res) => {
  2.   console.info('弱网状态变化:', res);
  3.   console.info('是否弱网:', res.weakNet);
  4.   console.info('网络类型:', res.networkType);
  5. };
  6. has.onNetworkWeakChange(onNetworkWeakChange);
复制代码

返回字段包括 weakNet,表示当前是否处于弱网状态;networkType 表示当前网络类型,但这里只会出现 cellular 和 wifi 两种。移除方式与网络状态监听相同:
  1. has.offNetworkWeakChange(onNetworkWeakChange);
复制代码

弱网检测的实际意义比较大。进入弱网后,可以降低图片质量、减少请求频率,或者提示用户当前网络较差。相比让用户一直等转圈,这种降级和反馈体验更好。

在页面生命周期里管理监听

实际项目中,可以在页面生命周期里注册和移除监听,并结合 getNetworkType 获取初始状态。核心思路是把回调函数挂到 this 上,用下划线前缀区分,便于在页面销毁时精确移除:
  1. Page({
  2.   data: {
  3.     networkType: '未知',
  4.     isConnected: true,
  5.     isWeakNet: false,
  6.     localIP: '',
  7.   },
  8.   onReady() {
  9.     this.getNetworkInfo();
  10.   },
  11.   onUnload() {
  12.     this.removeListeners();
  13.   },
  14.   getNetworkInfo() {
  15.     has.getNetworkType({
  16.       success: (res) => {
  17.         this.setData({ networkType: res.networkType });
  18.       }
  19.     });
  20.     this._onNetworkStatusChange = (res) => {
  21.       this.setData({
  22.         isConnected: res.isConnected,
  23.         networkType: res.networkType
  24.       });
  25.       if (!res.isConnected) {
  26.         console.warn('网络已断开');
  27.       }
  28.     };
  29.     has.onNetworkStatusChange(this._onNetworkStatusChange);
  30.     this._onNetworkWeakChange = (res) => {
  31.       this.setData({ isWeakNet: res.weakNet });
  32.       if (res.weakNet) {
  33.         console.warn('进入弱网状态');
  34.       }
  35.     };
  36.     has.onNetworkWeakChange(this._onNetworkWeakChange);
  37.   },
  38.   getLocalIP() {
  39.     has.getLocalIPAddress({
  40.       success: (res) => {
  41.         this.setData({ localIP: res.localip });
  42.       },
  43.       fail: (err) => {
  44.         console.error('获取 IP 失败:', err);
  45.         this.setData({ localIP: '获取失败' });
  46.       }
  47.     });
  48.   },
  49.   removeListeners() {
  50.     if (this._onNetworkStatusChange) {
  51.       has.offNetworkStatusChange(this._onNetworkStatusChange);
  52.     }
  53.     if (this._onNetworkWeakChange) {
  54.       has.offNetworkWeakChange(this._onNetworkWeakChange);
  55.     }
  56.   }
  57. });
复制代码

权限配置

在 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,要对未知类型做兜底。

结合请求做弱网降级

只监听弱网还不够,业务层要响应。可以在请求封装里先判断网络状态:
  1. function requestWithNetCheck(options) {
  2.   has.getNetworkType({
  3.     success: (res) => {
  4.       if (res.networkType === 'none') {
  5.         console.warn('无网络连接,跳过请求');
  6.         if (options.fail) {
  7.           options.fail({ errMsg: '无网络连接' });
  8.         }
  9.         return;
  10.       }
  11.       has.request({
  12.         url: options.url,
  13.         method: options.method || 'GET',
  14.         data: options.data,
  15.         success: options.success,
  16.         fail: options.fail
  17.       });
  18.     }
  19.   });
  20. }
复制代码

更进一步,可以在弱网状态下降低请求频率,例如把轮询间隔从 5 秒改成 30 秒,或取消非关键请求。这些逻辑不复杂,但对用户体验提升明显。

给用户可见的 UI 反馈

监听到网络变化后,除了业务降级,UI 也要给出反馈。例如在页面顶部显示网络状态提示条:
  1. Page({
  2.   data: {
  3.     showNetTip: false,
  4.     netTipText: '',
  5.     netTipType: 'warn',
  6.   },
  7.   onReady() {
  8.     this._onNetworkStatusChange = (res) => {
  9.       if (!res.isConnected) {
  10.         this.setData({
  11.           showNetTip: true,
  12.           netTipText: '网络已断开,请检查网络连接',
  13.           netTipType: 'error'
  14.         });
  15.       } else {
  16.         this.setData({
  17.           showNetTip: true,
  18.           netTipText: '已恢复' + res.networkType + '网络',
  19.           netTipType: 'success'
  20.         });
  21.         setTimeout(() => {
  22.           this.setData({ showNetTip: false });
  23.         }, 3000);
  24.       }
  25.     };
  26.     has.onNetworkStatusChange(this._onNetworkStatusChange);
  27.   }
  28. });
复制代码

顶部提示条比直接弹 modal 框侵入性更小,不会打断用户操作。

多页面与全局监听

如果多个页面都需要监听网络状态,每个页面各自注册和移除即可。ASCF 的监听按页面隔离,页面销毁时会自动清理。若要做 App 级全局网络状态管理,可以在 app.js 的 onCreate 里注册全局监听,再通过事件总线或全局状态同步给各个页面:
  1. App({
  2.   data: {
  3.     globalNetworkType: 'unknown',
  4.     globalIsConnected: true,
  5.   },
  6.   onCreate() {
  7.     has.onNetworkStatusChange((res) => {
  8.       this.data.globalNetworkType = res.networkType;
  9.       this.data.globalIsConnected = res.isConnected;
  10.       // 这里可以触发全局事件通知各页面
  11.     });
  12.   }
  13. });
复制代码

不过大多数场景按页面管理就够了,除非元服务对网络依赖特别重,否则不必把监听架构做得太复杂。

兼容与总结

onNetworkWeakChange 是 1.0.12 才加入的,如果需要兼容低版本 ASCF,记得做降级处理,不要直接调用导致报错。总体来说,网络状态感知看起来简单,但做好权限区分、监听引用管理、弱网降级和 UI 反馈,就能明显改善弱网和切换网络场景下的用户体验。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-14 16:56 , Processed in 0.022405 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部