Flutter Network Quality Monitor 开发实践

4 阅读6分钟

前言:

  • 最近抽了一些下班后的时间,把项目里“网络状态判断”这块从零散业务代码中抽离出来,做成了一个可复用的 Flutter 插件:network_quality_monitor。一开始目标很简单,只想知道当前是否联网,但真正落到项目后发现,业务侧更关心的是“当前网络到底好不好”。
  • 所以这个插件最终不只做了连接状态,还补了网络类型识别、质量等级评估、实时监听,以及主动探测(RTT/下行估算)能力。这样页面可以基于网络质量做更细粒度的降级策略,而不是只用一个 isConnected 硬判断。
  • 本篇文章更偏实战一些,重点讲的是设计思路和落地方式,而不是单独讲 API。老规矩,先从整体思路开始。

正文:

当前项目中的 network_quality_monitor 使用,主要从下面几个维度来理解:

  1. 为什么要做网络质量监控插件
  2. 插件能力模型怎么设计
  3. Flutter 侧完整使用流程
  4. Android / iOS 原生实现思路
  5. 如何在业务页面做降级和兜底
  6. 常见误区和实践建议
  • 为什么要做网络质量监控插件

在很多项目里,网络判断通常只有一句:

  • 有网 / 没网

但真实业务里其实更复杂:

  • 用户虽然“有网”,但 RTT 很高
  • Wi-Fi 信号弱,接口频繁超时
  • 蜂窝网络抖动,实时场景体验断续
  • 前后台切换后网络能力变化很大

如果只靠 isConnected,页面只能做“是否可用”的粗判断。

而网络质量插件的目标是:

  • 给业务侧提供可操作的质量信号
  • 支持实时监听 + 主动探测
  • 让页面可以按网络质量动态调整策略

比如:

  • 质量差时降低图片质量

  • 质量差时暂停大文件上传

  • 实时场景下切换到低码率策略

  • 插件能力模型设计

当前插件核心模型是 NetworkQualityStatus,包含:

  • isConnected:当前是否联网
  • networkTypewifi / cellular / ethernet / none / other / unknown
  • qualityoffline / poor / fair / good / excellent / unknown
  • downlinkKbps:下行带宽估值(Android 有值,iOS 探测后可补)
  • rttMs:往返时延(主动探测时返回)
  • raw:原始结果透传(方便排障)

对应能力分为三类:

  1. 一次性查询:getCurrentStatus()
  2. 实时监听:onStatusChanged
  3. 主动探测:probeQuality({probeUrl, timeoutMs})

这种设计有个好处:

  • 业务可以按场景选择成本更低的能力

例如:

  • 普通列表页只用 getCurrentStatus

  • 音视频页使用 onStatusChanged

  • 上传前调用一次 probeQuality

  • Flutter 侧完整使用流程

下面以“页面进入后获取网络状态 + 开始监听 + 手动测速”这个常见场景举例。

final monitor = NetworkQualityMonitor();

// 1. 一次性获取当前状态
final current = await monitor.getCurrentStatus();

// 2. 监听网络变化
final sub = monitor.onStatusChanged.listen((status) {
  // 根据质量动态调整 UI 或请求策略
  // e.g. status.quality == NetworkQuality.poor
});

// 3. 业务关键时刻做主动探测(比如上传前)
final probe = await monitor.probeQuality(
  probeUrl: 'https://www.baidu.com/favicon.ico',
  timeoutMs: 1500,
);

// 页面销毁记得取消监听
sub.cancel();

如果你是 Store / ViewModel 架构,建议把监听和探测放在 store 里,页面只订阅状态。

  • Android 实现思路

Android 侧主要分两层:

  1. 被动监听能力:ConnectivityManager + NetworkCallback
  2. 主动探测能力:HttpURLConnection 计算 RTT,并结合带宽估值做质量判断

被动监听主要做:

  • 网络可用变化
  • 网络能力变化
  • 网络类型变化

主动探测主要做:

  • 对目标 URL 发起轻量请求
  • 计算请求耗时作为 rttMs
  • 结合 downlinkKbpsrttMs 生成质量等级

这两层组合起来,比单纯监听系统网络状态更贴近真实体验。

  • iOS 实现思路

iOS 侧基于:

  1. NWPathMonitor:监听当前网络路径和类型
  2. URLSession:主动探测 RTT(必要时补充质量判断)

NWPathMonitor 非常适合做持续监听,但它不是完整测速工具。 所以在关键场景里配合一次 URLSession 探测,效果会更稳定。

也就是说:

  • 被动监听负责“持续感知”

  • 主动探测负责“关键时刻校准”

  • 质量分级建议(可按业务调整)

当前插件是一个通用分级策略,建议你在业务里再做一层映射:

  • excellent:可开高质量能力(高清图、并发上传)
  • good:默认策略
  • fair:控制请求并发,减少预加载
  • poor:启用保守策略(低清、延迟加载、弱网提示)
  • offline:离线兜底

关键点是:

  • 插件负责给“事实”

  • 业务负责做“策略”

  • 业务落地建议

如果你的页面依赖网络强度,建议这样组织:

  1. 页面初始化拿一次 getCurrentStatus
  2. 页面可见期监听 onStatusChanged
  3. 上传/实时前做 probeQuality
  4. 把质量状态映射到统一降级策略

例如:

  • 录音转写场景:poor 时降低帧率或提高重试间隔

  • 图片流场景:fair/poor 时切换低清图源

  • 下载场景:poor 时暂停后台预下载

  • 常见误区
  • 误区1:只用 isConnected 判断体验

用户“有网”不代表可用体验好。建议至少结合 quality

  • 误区2:频繁主动探测

主动探测是有成本的,不建议高频调用。建议在关键操作前触发一次。

  • 误区3:把策略写死在插件里

插件尽量做通用能力,业务策略放在项目层更灵活。

  • 误区4:监听不释放

onStatusChanged 必须在页面/模块销毁时取消订阅。

  • 项目中的架构总结

这轮改造后,网络质量相关逻辑已经形成了比较清晰的链路:

  • 插件层提供统一网络状态能力
  • store/viewmodel 负责组合与策略分发
  • 页面按状态做局部刷新与降级提示
  • 关键操作前用主动探测做校准

这样做的价值是:

  • 多项目可复用
  • 页面逻辑更轻
  • 异常排查更直接
  • 弱网场景体验更可控

结束:

网络质量监控这件事,真正有价值的点不在“拿到一个状态”,而在于:

  • 能不能把网络变化转成业务可执行策略
  • 能不能在关键场景前提前感知风险
  • 能不能把弱网体验做成可控而不是被动兜底

这个插件目前已经具备基础可用能力,后续还可以继续做:

  • 周期性探测
  • 抖动估算
  • 质量变化防抖
  • 场景化策略模板

如果你项目里也有实时、上传、弱网敏感场景,建议尽早把“网络质量”从页面逻辑里抽出来,收益会比想象中大。

声明:

仅开源供大家学习使用,禁止从事商业活动,如出现一切法律问题自行承担。

仅学习使用,如有侵权,造成影响,请联系删除,谢谢。