网络状态监听&WiFi信息获取:弱网提示、断网兜底方案
网络状态监听&WiFi信息获取:弱网提示、断网兜底方案
几乎所有鸿蒙应用都要联网,接口请求、图片加载、数据同步都依赖网络。但很多开发者只关注"能不能请求成功",忽略了网络状态变化的处理——用户切到地下车库WiFi断了,页面还在转圈;电梯里信号弱,接口超时了也不提示。最后用户以为APP卡了,直接退出。本文基于最新鸿蒙API,把网络状态监听、WiFi信息获取、弱网提示和断网兜底的完整落地流程讲清楚,代码可以直接复制到项目里跑。
01 权限前置与网络状态监听
网络监听需要先配置权限,获取WiFi信息还需要定位权限,因为WiFi位置信息涉及用户隐私。module.json5里需要声明两个权限:
"requestPermissions": [
{
"name": "ohos.permission.GET_NETWORK_INFO",
"reason": "$string:network_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.GET_WIFI_INFO",
"reason": "$string:wifi_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
GET_NETWORK_INFO用来监听网络状态变化,GET_WIFI_INFO用来获取WiFi详细信息。如果还要扫描周边WiFi列表,还需要加定位权限,这里我们只获取当前连接的WiFi信息,不需要扫描。网络状态监听的核心是netConnection对象,注册回调后,网络变化会自动通知:
import { connection } from '@kit.NetworkKit';
const netConn = connection.createNetConnection();
// 网络可用回调
netConn.on('netAvailable', (data: connection.NetCapabilities) => {
console.info('网络可用,类型:', data.bearerTypes);
// WiFi: BEARER_WIFI, 蜂窝: BEARER_CELLULAR
});
// 网络丢失回调(断网)
netConn.on('netLost', (data: connection.NetHandle) => {
console.info('网络已断开');
// 这里触发断网兜底逻辑
});
// 网络能力变化回调(弱网切换)
netConn.on('netCapabilitiesChange', (data: connection.NetCapabilities) => {
console.info('网络能力变化:', data.bearerTypes);
// 可以在这里判断是否从WiFi切到蜂窝
});
// 注册监听,开始接收网络状态变化
netConn.register(true);
// 页面退出时记得反注册,不然会内存泄漏
// netConn.unregister();
几个关键回调的触发时机:
-
netAvailable:网络恢复可用时触发,刚开机、从断网恢复都会走这里
-
netLost:网络完全断开时触发,关WiFi、飞行模式、信号全丢
-
netCapabilitiesChange:网络类型切换时触发,比如WiFi切到4G,或者网络质量变化
register(true)里的true表示立即返回一次当前网络状态,不用等下次变化。
02 获取当前网络类型与WiFi信息
除了监听状态变化,很多场景还需要主动获取当前网络的详细信息:当前是WiFi还是蜂窝、WiFi信号强度是多少、SSID是什么。
import { connection } from '@kit.NetworkKit';
import { wifiManager } from '@kit.ConnectivityKit';
// 获取当前默认网络
async function getCurrentNetwork() {
const netHandle = connection.getDefaultNet();
const capabilities = connection.getNetCapabilities(netHandle);
// 判断网络类型
const isWifi = capabilities.bearerTypes.includes(
connection.NetBearType.BEARER_WIFI
);
const isCellular = capabilities.bearerTypes.includes(
connection.NetBearType.BEARER_CELLULAR
);
console.info('WiFi:', isWifi, '蜂窝:', isCellular);
return { isWifi, isCellular, capabilities };
}
WiFi详细信息通过wifiManager获取:
async function getWifiInfo() {
const wifi = wifiManager.getWifiInstance();
// 先判断WiFi是否打开
if (!wifi.isWifiActive()) {
console.info('WiFi未开启');
return null;
}
const info = wifi.getLinkedInfo();
console.info('WiFi名称:', info.ssid);
console.info('信号强度:', info.rssi); // -50很好,-80以下就是弱网
console.info('连接速度:', info.linkSpeed); // 单位Mbps
console.info('频率:', info.frequency); // 2.4G还是5G
return info;
}
rssi是WiFi信号强度,数值越大信号越好:
-
-50以上:信号极好,下载看视频无压力
-
-50到-70:信号良好,正常使用没问题
-
-70到-80:信号偏弱,加载图片会慢
-
-80以下:信号很差,接口容易超时
这个数值可以直接用来判断弱网,不用自己算。
03 弱网检测与提示实现
弱网不是完全断网,而是能用但很慢。用户感觉页面卡、图片加载不出来,但又不知道是网络的问题。这时候主动给个提示,体验会好很多。
弱网判断可以从两个维度入手:WiFi信号强度,以及接口请求耗时。
import { promptAction } from '@kit.ArkUI';
let isWeakNetwork: boolean = false;
// 根据WiFi信号判断弱网
function checkWifiWeakness(rssi: number): boolean {
// rssi低于-75就算弱网
return rssi < -75;
}
// 接口请求超时统计,连续超时就算弱网
let timeoutCount: number = 0;
const MAX_TIMEOUT = 2; // 连续2次超时判定弱网
function onRequestSuccess() {
timeoutCount = 0;
}
function onRequestTimeout() {
timeoutCount++;
if (timeoutCount >= MAX_TIMEOUT && !isWeakNetwork) {
isWeakNetwork = true;
promptAction.showToast({ message: '当前网络较慢,建议切换网络' });
}
}
function onNetworkRecover() {
isWeakNetwork = false;
timeoutCount = 0;
}
弱网提示不要做成弹窗打断用户,用顶部横幅或者轻量Toast就够了。用户知道网络不好,自然会自己切换。弹窗太强硬反而引起反感。
还有一个细节:弱网时可以自动降低图片加载质量。比如列表页的缩略图,弱网下加载低清版本,WiFi下加载高清版本,这样加载速度会快很多。
04 断网兜底方案设计
完全断网的时候,不能让用户对着一个白屏或者转圈的加载页发呆。断网兜底的核心思路是:检测到断网 → 显示兜底页面 → 网络恢复 → 自动重试。
页面级别的断网兜底,可以封装成一个通用组件:
@Entry
@Component
struct NetworkGuard {
@State isOffline: boolean = false;
private netConn: connection.NetConnection = connection.createNetConnection();
aboutToAppear() {
// 监听网络状态
this.netConn.on('netLost', () => {
this.isOffline = true;
});
this.netConn.on('netAvailable', () => {
if (this.isOffline) {
this.isOffline = false;
// 网络恢复,自动重新加载数据
this.retryLoadData();
}
});
this.netConn.register(true);
}
aboutToDisappear() {
this.netConn.unregister();
}
async retryLoadData() {
// 重新请求当前页面数据
console.info('网络恢复,自动重试');
}
build() {
Stack() {
// 正常内容
Column() {
Text('页面主内容').fontSize(20)
}
.visibility(this.isOffline ? Visibility.Hidden : Visibility.Visible)
// 断网兜底页
Column() {
Image($r('app.media.no_network'))
.width(120)
.height(120)
Text('网络连接已断开')
.fontSize(18)
.margin({ top: 16 })
Button('点击重试')
.margin({ top: 24 })
.onClick(() => {
this.retryLoadData();
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor('#f5f5f5')
.visibility(this.isOffline ? Visibility.Visible : Visibility.Visible)
}
.width('100%')
.height('100%')
}
}
兜底页面的几个关键点:
-
要有重试按钮,用户点一下就能手动刷新,不用退出页面重进
-
网络恢复自动重试,不用用户手动点,体验更好
-
不要用弹窗,直接替换整个页面内容,层级更清晰
除了页面兜底,接口请求层面也要做断网处理。请求前先判断当前有没有网络,没网就直接走本地缓存或者返回错误,不用等接口超时,省时间。
05 完整网络管理工具类封装
把上面的逻辑封装成一个统一的网络管理类,项目里直接调用,不用每个页面都写一遍监听逻辑。
import { connection } from '@kit.NetworkKit';
import { wifiManager } from '@kit.ConnectivityKit';
type NetworkChangeListener = (isOnline: boolean, type: string) => void;
class NetworkManager {
private static instance: NetworkManager;
private netConn: connection.NetConnection;
private listeners: NetworkChangeListener[] = [];
private isOnline: boolean = true;
private networkType: string = 'unknown';
private constructor() {
this.netConn = connection.createNetConnection();
this.initListener();
}
static getInstance(): NetworkManager {
if (!NetworkManager.instance) {
NetworkManager.instance = new NetworkManager();
}
return NetworkManager.instance;
}
private initListener() {
this.netConn.on('netAvailable', (data) => {
this.isOnline = true;
this.networkType = data.bearerTypes.includes(
connection.NetBearType.BEARER_WIFI
) ? 'wifi' : 'cellular';
this.notifyListeners();
});
this.netConn.on('netLost', () => {
this.isOnline = false;
this.networkType = 'none';
this.notifyListeners();
});
this.netConn.register(true);
}
// 页面注册监听
addListener(listener: NetworkChangeListener) {
this.listeners.push(listener);
// 注册时立刻返回当前状态
listener(this.isOnline, this.networkType);
}
// 页面销毁时移除监听,防止内存泄漏
removeListener(listener: NetworkChangeListener) {
this.listeners = this.listeners.filter(l => l !== listener);
}
private notifyListeners() {
this.listeners.forEach(l => l(this.isOnline, this.networkType));
}
// 主动判断是否联网
isNetworkAvailable(): boolean {
return this.isOnline;
}
// 判断是否是WiFi
isWifi(): boolean {
return this.networkType === 'wifi';
}
// 获取WiFi信号强度
async getWifiRssi(): Promise<number> {
const wifi = wifiManager.getWifiInstance();
if (!wifi.isWifiActive()) return -100;
return wifi.getLinkedInfo().rssi;
}
}
// 使用方式
const netMgr = NetworkManager.getInstance();
// 页面里注册监听
netMgr.addListener((isOnline, type) => {
console.info('网络状态:', isOnline, type);
});
这样封装之后,任何页面只需要addListener就能收到网络变化通知,页面销毁时removeListener就行。不用每个页面都去创建netConnection,也不会出现重复注册的问题。
更多推荐




所有评论(0)