为什么要在元服务里处理网络状态
做元服务开发时,网络状态很容易被忽略,但它直接影响接口请求体验。用户在地铁里从 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 反馈,就能明显改善弱网和切换网络场景下的用户体验。 |