uni.onnetworkstatuschange是唯一能捕获精确网络切换的被动通知api,但仅前台有效,需在onshow中重注册、防抖比对状态、二次校验业务可用性。

uni.onNetworkStatusChange 是唯一能捕获精确切换的 API
它不是轮询,而是系统网络栈真正变化时的被动通知,比如 WiFi 断开瞬间、4G 切换到 5G、USB 网络共享启用等。但注意:uni.onNetworkStatusChange 只在 App 前台运行时有效,切到后台立即停止回调,这是 iOS/Android 系统限制,不是 bug。
常见失效场景包括:
- App 启动后未触发
onShow就直接进入页面,监听没注册 - iOS 真机未开启「后台运行」权限(即使不依赖后台,部分机型也会干扰前台监听)
- 华为 EMUI、小米 MIUI 等定制 ROM 默认屏蔽后台网络广播,需手动在
manifest.json补android.permission.ACCESS_NETWORK_STATE - WiFi 已连但 DHCP 还没分配 IP,
res.isConnected仍为false,此时状态是“假断网”
必须在 onShow 中重新注册监听句柄
uni.onNetworkStatusChange 的监听句柄在 App 切后台后会被系统释放,回到前台时不会自动恢复。很多开发者只在 main.js 或 App.vue 的 created 里注册一次,结果切后台再回来就收不到回调。
实操建议:
- 把监听注册逻辑统一写在
App.vue的onShow钩子中,确保每次前台可见都重装 - 避免在页面级组件里重复注册,容易造成句柄堆积或冲突
- 注册前先调用
uni.getNetworkType获取当前快照,作为初始状态,防止首次回调延迟导致界面 stale
防抖 + 状态比对才能避免地铁式弹窗
隧道穿行、电梯间、企业内网 DHCP 延迟等场景,会让 res.isConnected 在 true/false 间高频跳变。直接每次触发都 uni.showToast,用户会看到“网络已断开→已恢复→已断开…”连环闪现。
推荐做法:
- 用一个全局变量(如
window.__lastConnected)缓存上一次状态,只在res.isConnected === false && window.__lastConnected === true时才触发提示 - 加 1.5 秒防抖:用
setTimeout缓存判断,连续两次false才认定为真实断网 - 限制单日最多弹 3 次,用
uni.getStorageSync('offline_count')+ 时间戳控制 - 只在当前活跃页(
getCurrentPages().pop()?.route === 'pages/home/index')才执行 UI 提示,避免后台页误触
isConnected === true 不等于业务可用
系统返回 isConnected: true 和 networkType: 'wifi',只代表链路层通了,不代表你能访问服务器。比如连上了没配 DNS 的热点、公司内网防火墙拦截、运营商 NAT 失效等,都会导致“看着有网,实际打不开接口”。
关键补救措施:
- 对核心操作(如上传、同步、登录)做二次校验:发一个轻量
uni.request到你自己的健康接口(如/api/health),超时即判定为“假连网” - 不要仅依赖
res.networkType做策略分发——它只返回wifi/4g/5g,无法区分“CMCC-5G”和“TP-LINK_XXXX”,真要识别局域网设备,得额外调uni.getConnectedWifi(需定位权限 + 平台兼容处理) - iOS 必须提前申请
scope.userLocation权限,否则networkType恒为unknown或none;Android 10+ 同样依赖该权限获取准确类型
最容易被忽略的一点:网络状态切换本身是可靠的,但它的输出不能直接映射成业务逻辑。你得自己定义“什么才算真正可用”,而不是相信系统给的那个 isConnected。











