Flutter 三方库 connectivity_plus 的鸿蒙化适配与网络状态管理实战
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
一、背景与问题域
在移动应用开发中,网络连接状态的管理是构建健壮用户体验的核心课题。用户日常使用手机的过程中,网络状态变化是极为频繁的场景:进入电梯时信号衰减、地铁穿越基站覆盖边界、咖啡厅里从移动数据切换到公共 WiFi、地下车库完全失去信号------这些状态切换如果应用处理不当,轻则导致页面卡顿、白屏,重则导致用户操作数据丢失、核心流程中断。
传统开发中,开发者往往在每个需要网络请求的页面分别处理网络异常。这种做法存在三个显著缺陷:
第一,代码重复。每个涉及网络请求的页面都需要编写相似的网络检测逻辑,包括离线判断、网络恢复检测、错误提示等,造成大量冗余代码。
第二,状态不一致。分散在各页面的网络检测逻辑缺乏统一协调机制,可能出现部分页面已提示离线而其他页面仍在发起请求的情况,用户体验碎片化。
第三,维护成本高。当网络检测逻辑需要调整时(如增加 WiFi 切换到移动网络的特殊处理),需要在多个文件、多处位置逐一修改,极易遗漏。
针对上述问题,我们需要在 Flutter for OpenHarmony 项目中构建一套统一、完善的网络状态监听与响应体系。connectivity_plus 作为 Flutter 生态中网络连接状态监听领域最成熟的三方库,自然成为首选方案。
二、connectivity_plus 库的特性与 OH 平台能力评估
2.1 库的核心能力概述
connectivity_plus 由 Flutter Community 团队维护,是 Flutter 官方推荐的跨平台网络状态监听解决方案。该库的核心价值在于提供了一套统一抽象的 API,能够屏蔽底层各操作系统网络状态获取机制的差异,为开发者提供一致的使用体验。
主动查询能力 :通过 checkConnectivity() 方法,开发者可以随时获取设备当前的连接状态。这是异步方法,返回值为 List<ConnectivityResult> 枚举数组,原因是现代设备可能同时保持多种网络连接(例如手机同时连接 WiFi 和蓝牙网络)。
dart
final results = await connectivity.checkConnectivity();
for (final result in results) {
if (result == ConnectivityResult.wifi) {
print('当前已连接 WiFi');
}
}
被动监听能力 :通过 onConnectivityChanged 流,开发者可以订阅网络状态变化事件。与主动查询不同,被动监听不需要轮询,操作系统会在网络状态实际发生变化时主动通知应用,因此具有更好的实时性和更低的资源消耗。
dart
connectivity.onConnectivityChanged.listen((results) {
if (results.contains(ConnectivityResult.wifi)) {
print('WiFi 已连接');
} else if (results.contains(ConnectivityResult.none)) {
print('当前无网络连接');
}
});
2.2 支持的连接类型
connectivity_plus 对网络连接类型的抽象覆盖了主流应用场景:
| 枚举值 | 含义 | OpenHarmony 支持情况 |
|---|---|---|
wifi |
无线局域网 | 完全支持 |
mobile |
蜂窝移动网络(4G/5G) | 完全支持 |
ethernet |
以太网有线网络 | 完全支持 |
bluetooth |
蓝牙共享网络 | 完全支持 |
vpn |
虚拟专用网络 | 完全支持 |
other |
其他网络类型 | 完全支持 |
none |
无有效网络连接 | 完全支持 |
从上表可以看出,connectivity_plus 所定义的七种连接类型在 OpenHarmony 平台均有对应实现。需要特别说明的是 none 的判定逻辑:当系统返回的列表为空,或列表中唯一元素为 ConnectivityResult.none 时,表明设备当前没有有效的网络连接。
2.3 选型决策依据
在评估网络状态监听方案时,我们主要从以下四个维度进行比较:
成熟度与稳定性。connectivity_plus 自 2018 年发布以来持续维护,API 设计经历了多个版本的迭代优化,整体稳定。相较于自研方案或新兴库,其行为边界清晰、已知问题有充分文档记录。
跨平台一致性。Android、iOS、Web、Linux、Windows、macOS 以及 OpenHarmony 共用同一套 Dart API。当业务同时覆盖多端时,开发者无需为每个平台分别学习不同的网络状态获取方式。
社区活跃度。该库由 Flutter Community 维护,在 pub.dev 上的周下载量超过百万,issues 响应及时。与 OpenHarmony 的适配工作由社区持续推进,版本更新中对 OH 平台的支持持续完善。
与 Riverpod 的协同性。connectivity_plus 本身仅提供基础的监听能力,高级功能(如网络恢复自动刷新、状态历史记录、便捷派生 Provider)需要开发者自行封装。我们选择将网络状态与 Riverpod 状态管理体系深度整合,实现更高级别的工程化实践。
三、数据模型设计
3.1 连接类型枚举
我们首先定义一套面向业务的数据模型,将 connectivity_plus 的 ConnectivityResult 枚举映射为更具业务语义的 ConnectionType 枚举:
dart
/// 网络连接类型枚举
///
/// 覆盖 OpenHarmony 平台的主要网络形态,
/// 同时兼容 connectivity_plus 的 ConnectivityResult 定义
enum ConnectionType {
/// 无线局域网
wifi,
/// 蜂窝移动网络(4G/5G)
mobile,
/// 以太网有线网络
ethernet,
/// 蓝牙共享网络
bluetooth,
/// 虚拟专用网络
vpn,
/// 其他网络类型
other,
/// 无网络连接
none,
}
3.2 网络连接状态信息模型
ConnectivityInfo 是网络状态的核心数据载体,它不仅包含原始的连接类型列表,还提供了多个派生属性,简化页面层的使用:
dart
/// 网络连接状态数据模型
class ConnectivityInfo {
/// 当前网络连接类型列表
/// 一个设备可能同时保持多种网络连接
final List<ConnectionType> connectionTypes;
/// 是否已连接(任意有效网络)
final bool isConnected;
/// 是否为高质量网络(WiFi 或以太网,适合大数据传输)
final bool isHighQuality;
/// 上次状态变化的时间戳
final DateTime? lastChangedAt;
/// 状态变化历史记录(用于离线时长计算等)
final List<ConnectivityHistoryEntry> history;
/// 获取主要连接类型(用于 UI 显示)
/// 优先级:WiFi > 以太网 > 移动网络 > 其他
ConnectionType? get primaryType {
if (connectionTypes.isEmpty || connectionTypes.contains(ConnectionType.none)) {
return null;
}
if (connectionTypes.contains(ConnectionType.wifi)) return ConnectionType.wifi;
if (connectionTypes.contains(ConnectionType.ethernet)) return ConnectionType.ethernet;
if (connectionTypes.contains(ConnectionType.mobile)) return ConnectionType.mobile;
return connectionTypes.first;
}
/// 获取连接类型的友好显示名称
String get connectionTypeName {
final type = primaryType;
if (type == null) return '无网络';
switch (type) {
case ConnectionType.wifi: return 'WiFi';
case ConnectionType.mobile: return '移动网络';
case ConnectionType.ethernet: return '以太网';
case ConnectionType.bluetooth: return '蓝牙';
case ConnectionType.vpn: return 'VPN';
case ConnectionType.other: return '其他网络';
case ConnectionType.none: return '无网络';
}
}
/// 判断是否为特定连接类型
bool isType(ConnectionType type) => connectionTypes.contains(type);
/// 计算离线持续时长
/// 仅在当前处于离线状态时返回有意义的值
Duration? get offlineDuration {
if (isConnected) return null;
final lastOffline = history
.where((e) => e.fromConnected && !e.toConnected)
.lastOrNull;
if (lastOffline == null) return null;
return DateTime.now().difference(lastOffline.timestamp);
}
}
3.3 状态变化历史记录模型
为了支持离线时长计算、状态变化统计等高级功能,我们设计了 ConnectivityHistoryEntry 模型:
dart
/// 网络状态变化历史条目
class ConnectivityHistoryEntry {
/// 变化发生的时间戳
final DateTime timestamp;
/// 变化前的连接状态
final bool fromConnected;
/// 变化后的连接状态
final bool toConnected;
/// 变化前的连接类型列表
final List<ConnectionType> fromTypes;
/// 变化后的连接类型列表
final List<ConnectionType> toTypes;
/// 变化的语义类型
final ConnectivityChangeType changeType;
/// 是否为离线到联网的切换
bool get wasReconnected => !fromConnected && toConnected;
/// 是否为联网到离线的切换
bool get wasDisconnected => fromConnected && !toConnected;
}
/// 网络状态变化类型枚举
enum ConnectivityChangeType {
offlineToOnline, // 离线 → 联网
onlineToOffline, // 联网 → 离线
wifiToMobile, // WiFi → 移动网络
mobileToWifi, // 移动网络 → WiFi
wifiToEthernet, // WiFi → 以太网
ethernetToWifi, // 以太网 → WiFi
typeChanged, // 其他类型的网络类型切换
initial, // 初始状态
}
3.4 OH 平台原生类型映射
OpenHarmony 原生网络状态以整数值形式表示,通过平台通道传递给 Flutter 层。以下是映射关系的对照说明:
| OH 原生值 | OH 类型名 | 对应 ConnectionType |
|---|---|---|
| 0 | NONE | none |
| 1 | WIFI | wifi |
| 2 | CELLULAR | mobile |
| 3 | ETHERNET | ethernet |
| 4 | VPN | vpn |
| 5 | BLUETOOTH | bluetooth |
| 6 | OTHER | other |
这一映射关系定义在 ConnectivityInfo.fromOHNative 工厂构造方法中,为未来通过 MethodChannel 直接调用 OH 原生 API 预留了扩展空间。
四、服务层实现
4.1 ConnectivityService 架构设计
ConnectivityService 是网络状态管理的核心服务类,采用单例模式确保全局唯一实例。其职责包括:初始化并启动网络状态监听、接收平台层推送的状态变化事件、管理状态历史记录、对外暴露网络状态流、以及维护网络恢复和断开的回调注册机制。
dart
/// 网络连接状态服务
///
/// 负责网络状态监听、状态查询、历史管理及 OH 平台适配
class ConnectivityService {
static ConnectivityService? _instance;
static ConnectivityService get instance =>
_instance ??= ConnectivityService._();
ConnectivityService._();
/// connectivity_plus 的 Connectivity 实例(跨平台统一入口)
final Connectivity _connectivity = Connectivity();
/// 当前网络状态
ConnectivityInfo _currentInfo = ConnectivityInfo.empty();
/// 网络状态变化流(广播,供多个订阅者使用)
final StreamController<ConnectivityInfo> _connectivityController =
StreamController<ConnectivityInfo>.broadcast();
/// 网络状态变化历史
final List<ConnectivityHistoryEntry> _history = [];
/// 标记是否正在监听
bool _isListening = false;
/// 上一次连接状态(用于检测变化方向)
bool? _lastConnected;
/// 网络恢复时的回调列表
final List<Function(ConnectivityInfo)> _onNetworkRestoredCallbacks = [];
/// 网络断开时的回调列表
final List<Function(ConnectivityInfo)> _onNetworkLostCallbacks = [];
/// 获取网络状态流
Stream<ConnectivityInfo> get connectivityStream =>
_connectivityController.stream;
/// 获取当前网络状态(同步访问)
ConnectivityInfo get currentInfo => _currentInfo;
/// 获取历史记录(不可变列表)
List<ConnectivityHistoryEntry> get history =>
List.unmodifiable(_history);
}
4.2 初始化与监听启动
服务的初始化流程在 init() 方法中完成,首先获取初始网络状态,然后启动被动监听:
dart
/// 初始化并开始监听网络状态
Future<ConnectivityInfo> init() async {
await _updateConnectivity();
if (!_isListening) {
_startListening();
}
return _currentInfo;
}
/// 启动网络状态监听
void _startListening() {
if (_isListening) return;
_connectivity.onConnectivityChanged.listen(
_handleConnectivityChange,
onError: (error) {
debugPrint('[ConnectivityService] 监听错误: $error');
},
);
_isListening = true;
debugPrint('[ConnectivityService] 网络状态监听已启动');
}
4.3 网络状态变化处理
当操作系统推送网络状态变化事件时,_handleConnectivityChange 方法负责处理。其核心逻辑分为三步:更新内部状态、通知观察者、触发业务回调:
dart
/// 处理网络状态变化
void _handleConnectivityChange(List<ConnectivityResult> results) {
_updateConnectivity(results: results);
// 通知所有订阅者
_connectivityController.add(_currentInfo);
// 检测离线 → 联网切换,触发自动刷新
if (_currentInfo.isConnected && _lastConnected == false) {
debugPrint('[ConnectivityService] 网络已恢复,触发 onNetworkRestored 回调');
for (final callback in _onNetworkRestoredCallbacks) {
try {
callback(_currentInfo);
} catch (e) {
debugPrint('[ConnectivityService] onNetworkRestored 回调错误: $e');
}
}
}
// 检测联网 → 离线切换
if (!_currentInfo.isConnected && _lastConnected == true) {
debugPrint('[ConnectivityService] 网络已断开,触发 onNetworkLost 回调');
for (final callback in _onNetworkLostCallbacks) {
try {
callback(_currentInfo);
} catch (e) {
debugPrint('[ConnectivityService] onNetworkLost 回调错误: $e');
}
}
}
_lastConnected = _currentInfo.isConnected;
}
4.4 回调注册与注销机制
服务层提供了注册和注销回调的公开接口,业务层可以根据需要订阅网络恢复或网络断开事件:
dart
/// 注册网络恢复回调
void onNetworkRestored(Function(ConnectivityInfo) callback) {
_onNetworkRestoredCallbacks.add(callback);
}
/// 注册网络断开回调
void onNetworkLost(Function(ConnectivityInfo) callback) {
_onNetworkLostCallbacks.add(callback);
}
/// 移除网络恢复回调
void removeOnNetworkRestored(Function(ConnectivityInfo) callback) {
_onNetworkRestoredCallbacks.remove(callback);
}
/// 移除网络断开回调
void removeOnNetworkLost(Function(ConnectivityInfo) callback) {
_onNetworkLostCallbacks.remove(callback);
}
这种基于回调列表的设计允许应用同时注册多个网络恢复/断开处理逻辑,且各处理逻辑之间相互独立、不相互干扰。
4.5 历史记录管理
历史记录管理逻辑嵌入在 _updateConnectivity 方法中,当检测到连接状态发生实质性变化(而非仅仅类型切换)时,记录一条历史条目:
dart
/// 更新当前网络状态
Future<void> _updateConnectivity({List<ConnectivityResult>? results}) async {
try {
List<ConnectivityResult> connectivityResults;
if (results != null) {
connectivityResults = results;
} else {
connectivityResults = await _connectivity.checkConnectivity();
}
_recordHistory(connectivityResults);
_currentInfo = ConnectivityInfo.fromConnectivityResults(
connectivityResults,
lastChangedAt: DateTime.now(),
history: List.unmodifiable(_history),
);
} catch (e) {
debugPrint('[ConnectivityService] 获取网络状态失败: $e');
}
}
历史记录数量限制为最近 50 条,防止内存占用无限增长。当超过此上限时,最早的记录会被移除。
五、状态管理集成
5.1 Riverpod Provider 体系
我们将网络状态封装为 Riverpod 的 Notifier,使其能够与 Riverpod 生态无缝集成。ConnectivityNotifier 在 provider 首次被监听时自动初始化网络监听,并在状态变化时自动更新:
dart
/// 网络连接状态状态类
class ConnectivityState {
final ConnectivityInfo connectivityInfo;
final bool isListening;
final List<ConnectivityHistoryEntry> history;
final int changeCount;
const ConnectivityState({
required this.connectivityInfo,
this.isListening = false,
this.history = const [],
this.changeCount = 0,
});
factory ConnectivityState.initial() => const ConnectivityState(
connectivityInfo: ConnectivityInfo(
connectionTypes: [],
isConnected: false,
isHighQuality: false,
),
);
bool get isConnected => connectivityInfo.isConnected;
bool get isOffline => !connectivityInfo.isConnected;
String get connectionTypeName => connectivityInfo.connectionTypeName;
ConnectivityState copyWith({
ConnectivityInfo? connectivityInfo,
bool? isListening,
List<ConnectivityHistoryEntry>? history,
int? changeCount,
}) {
return ConnectivityState(
connectivityInfo: connectivityInfo ?? this.connectivityInfo,
isListening: isListening ?? this.isListening,
history: history ?? this.history,
changeCount: changeCount ?? this.changeCount,
);
}
}
/// 网络连接状态 Notifier
class ConnectivityNotifier extends Notifier<ConnectivityState> {
StreamSubscription<ConnectivityInfo>? _subscription;
@override
ConnectivityState build() {
_initConnectivity();
return ConnectivityState.initial();
}
Future<void> _initConnectivity() async {
await ConnectivityService.instance.init();
final info = ConnectivityService.instance.currentInfo;
state = state.copyWith(
connectivityInfo: info,
isListening: true,
);
_subscription?.cancel();
_subscription = ConnectivityService.instance.connectivityStream.listen(
_onConnectivityChanged,
onError: (error) { /* 错误处理 */ },
);
}
void _onConnectivityChanged(ConnectivityInfo info) {
state = state.copyWith(
connectivityInfo: info,
history: ConnectivityService.instance.history,
changeCount: state.changeCount + 1,
);
}
Future<void> checkConnectivity() async {
final info = await ConnectivityService.instance.checkConnectivity();
state = state.copyWith(connectivityInfo: info);
}
void clearHistory() {
ConnectivityService.instance.clearHistory();
state = state.copyWith(history: []);
}
}
/// 网络连接状态 Provider
final connectivityProvider =
NotifierProvider<ConnectivityNotifier, ConnectivityState>(() {
return ConnectivityNotifier();
});
5.2 便捷派生 Provider
为了简化页面层代码,我们基于 connectivityProvider 定义了多个派生 Provider,分别对应不同的判断维度:
dart
/// 是否已连接
final isConnectedProvider = Provider<bool>((ref) {
return ref.watch(connectivityProvider).isConnected;
});
/// 是否离线
final isOfflineProvider = Provider<bool>((ref) {
return ref.watch(connectivityProvider).isOffline;
});
/// 连接类型名称(用于 UI 显示)
final connectionTypeNameProvider = Provider<String>((ref) {
return ref.watch(connectivityProvider).connectionTypeName;
});
/// 是否为高质量网络(WiFi/以太网,适合大流量传输)
final isHighQualityNetworkProvider = Provider<bool>((ref) {
return ref.watch(connectivityProvider).connectivityInfo.isHighQuality;
});
/// 是否为 WiFi
final isWifiProvider = Provider<bool>((ref) {
return ref.watch(connectivityProvider).connectivityInfo
.isType(ConnectionType.wifi);
});
/// 是否为移动网络
final isMobileNetworkProvider = Provider<bool>((ref) {
return ref.watch(connectivityProvider).connectivityInfo
.isType(ConnectionType.mobile);
});
页面层使用时,只需引入对应的 Provider 即可,无需关心底层的服务初始化和状态同步细节:
dart
class _MyPageState extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// 简单判断是否离线
final isOffline = ref.watch(isOfflineProvider);
// 获取连接类型文字
final typeName = ref.watch(connectionTypeNameProvider);
return isOffline
? _buildOfflineView(typeName)
: _buildOnlineView();
}
}
六、网络恢复自动刷新机制
6.1 问题背景与设计目标
当设备从离线状态恢复网络连接时,用户最直接的期待是应用能够自动重新加载最新数据。以新闻阅读应用为例:用户在地铁中打开应用,浏览到一半地铁到站恢复网络,此时应用应当自动刷新列表,而非让用户手动下拉刷新。同样的场景也适用于电商商品列表、社交信息流、实时报价等需要持续保持数据新鲜度的场景。
自动刷新机制的设计目标是:网络恢复后,无需用户操作,应用自动触发已注册的数据刷新任务,并给予用户适当的视觉反馈。
6.2 NetworkRefreshManager 的实现
NetworkRefreshManagerNotifier 实现了注册-监听-触发的完整流程:
dart
/// 网络刷新管理器状态
class NetworkRefreshManagerState {
final Map<String, NetworkRefreshCallback> callbacks;
final int refreshCount;
final DateTime? lastRefreshTime;
const NetworkRefreshManagerState({
this.callbacks = const {},
this.refreshCount = 0,
this.lastRefreshTime,
});
NetworkRefreshManagerState copyWith({
Map<String, NetworkRefreshCallback>? callbacks,
int? refreshCount,
DateTime? lastRefreshTime,
}) {
return NetworkRefreshManagerState(
callbacks: callbacks ?? this.callbacks,
refreshCount: refreshCount ?? this.refreshCount,
lastRefreshTime: lastRefreshTime ?? this.lastRefreshTime,
);
}
}
/// 网络刷新管理器 Notifier
class NetworkRefreshManagerNotifier extends Notifier<NetworkRefreshManagerState> {
@override
NetworkRefreshManagerState build() {
// 监听网络恢复事件
ref.listen<ConnectivityState>(connectivityProvider, (previous, next) {
if (previous != null && !previous.isConnected && next.isConnected) {
_triggerAutoRefresh();
}
});
return const NetworkRefreshManagerState();
}
/// 注册自动刷新任务
void register({
required String key,
required Future<void> Function() onRefresh,
}) {
final callback = NetworkRefreshCallback(
key: key,
onRefresh: onRefresh,
lastRefreshTime: DateTime.now(),
);
final newCallbacks = Map<String, NetworkRefreshCallback>.from(state.callbacks);
newCallbacks[key] = callback;
state = state.copyWith(callbacks: newCallbacks);
}
/// 触发自动刷新
Future<void> _triggerAutoRefresh() async {
if (state.callbacks.isEmpty) return;
for (final callback in state.callbacks.values) {
try {
await callback.onRefresh();
} catch (e) {
// 单个刷新失败不影响其他任务
}
}
state = state.copyWith(
refreshCount: state.refreshCount + 1,
lastRefreshTime: DateTime.now(),
);
}
}
/// 网络刷新管理器 Provider
final networkRefreshManagerProvider =
NotifierProvider<NetworkRefreshManagerNotifier,
NetworkRefreshManagerState>(() {
return NetworkRefreshManagerNotifier();
});
6.3 页面集成示例
在具体的页面中,开发者只需要在初始化时注册刷新任务,网络恢复后刷新会自动触发:
dart
class PostListPage extends ConsumerStatefulWidget {
@override
ConsumerState<PostListPage> createState() => _PostListPageState();
}
class _PostListPageState extends ConsumerState<PostListPage> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
// 注册网络恢复时的自动刷新任务
ref.read(networkRefreshManagerProvider.notifier).register(
key: 'post_list',
onRefresh: () async {
await ref.read(postProvider.notifier).loadPosts();
},
);
});
}
void _onNetworkRestored() {
// 网络恢复时直接触发刷新,无需用户手动操作
ref.read(networkRefreshManagerProvider.notifier).refreshAll();
showSnackBar(context, '网络已恢复,正在刷新...');
}
}
七、离线提示 UI 组件
7.1 网络状态横幅组件
ConnectivityBanner 是一个包装型组件,将任意子组件包裹其中,同时在顶部或底部渲染网络状态提示。它能自动检测网络状态变化,分别展示离线横幅和网络恢复通知:
dart
/// 网络状态横幅组件
///
/// 使用方式:
/// ```dart
/// Scaffold(
/// body: ConnectivityBanner(
/// showOfflineBanner: true,
/// showRestoredNotification: true,
/// restoredNotificationDuration: 3,
/// child: MyPageContent(),
/// ),
/// )
/// ```
class ConnectivityBanner extends ConsumerStatefulWidget {
final Widget child;
final bool showOfflineBanner;
final bool showRestoredNotification;
final int restoredNotificationDuration;
const ConnectivityBanner({
super.key,
required this.child,
this.showOfflineBanner = true,
this.showRestoredNotification = true,
this.restoredNotificationDuration = 3,
});
}
横幅的视觉设计采用梯度配色:离线状态使用红橙渐变色传达警示感,网络恢复使用绿色渐变传达积极信号。恢复通知在展示指定时长后自动消失,避免干扰用户操作。
7.2 网络状态指示器
ConnectivityIndicator 是一个紧凑的状态指示组件,适合嵌入 AppBar 或抽屉菜单中:
dart
/// 简洁的网络状态指示器
class ConnectivityIndicator extends ConsumerWidget {
final double size;
final bool showLabel;
final VoidCallback? onTap;
const ConnectivityIndicator({
super.key,
this.size = 20,
this.showLabel = false,
this.onTap,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(connectivityProvider);
final isConnected = state.isConnected;
final info = state.connectivityInfo;
IconData icon;
Color color;
if (isConnected) {
switch (info.primaryType) {
case ConnectionType.wifi:
icon = Icons.wifi;
color = Colors.green;
break;
case ConnectionType.mobile:
icon = Icons.signal_cellular_alt;
color = Colors.blue;
break;
case ConnectionType.ethernet:
icon = Icons.settings_ethernet;
color = Colors.teal;
break;
default:
icon = Icons.signal_wifi_4_bar;
color = Colors.grey;
}
} else {
icon = Icons.wifi_off;
color = Colors.red;
}
return GestureDetector(
onTap: onTap,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: size, color: color),
if (showLabel) ...[
const SizedBox(width: 4),
Text(
info.connectionTypeName,
style: TextStyle(fontSize: size * 0.7, color: color),
),
],
],
),
);
}
}
在 AppBar 中的使用效果:在工作台页面右上角显示网络状态图标,点击后弹出详情底部菜单,展示当前连接类型、离线时长、状态变化次数等信息。
7.3 网络感知型 FutureBuilder
NetworkAwareFutureBuilder 是面向网络请求场景的便捷封装。当网络不可用时,它显示友好的离线提示而非原始错误;网络恢复时,自动重新发起请求:
dart
/// 网络状态友好的 FutureBuilder 包装器
class NetworkAwareFutureBuilder<T> extends ConsumerWidget {
final Future<T> Function() future;
final Widget Function(BuildContext context, T data) onSuccess;
final Widget Function(BuildContext context)? onLoading;
final Widget Function(BuildContext context, ConnectivityInfo? info)?
onNetworkError;
final Widget Function(BuildContext context, Object error, StackTrace?)?
onError;
const NetworkAwareFutureBuilder({
super.key,
required this.future,
required this.onSuccess,
this.onLoading,
this.onNetworkError,
this.onError,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(connectivityProvider);
if (!state.isConnected) {
return onNetworkError?.call(context, state.connectivityInfo) ??
_DefaultNetworkErrorWidget(info: state.connectivityInfo);
}
return FutureBuilder<T>(
future: future(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting ||
snapshot.connectionState == ConnectionState.active) {
return onLoading?.call(context) ??
const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return onError?.call(context, snapshot.error!, snapshot.stackTrace) ??
_DefaultErrorWidget(error: snapshot.error!);
}
return onSuccess(context, snapshot.data as T);
},
);
}
}
使用示例:
dart
NetworkAwareFutureBuilder<List<Post>>(
future: () => postService.fetchPosts(),
onSuccess: (context, posts) => PostListView(posts: posts),
onLoading: () => const Center(child: CircularProgressIndicator()),
onNetworkError: (context, info) => OfflineView(
message: '网络不可用,无法加载内容',
onRetry: () => ref.read(postProvider.notifier).loadPosts(),
),
)
八、网络状态管理页面
独立的网络状态管理页面 (/connectivity) 提供了网络状态的全景视图,包括四个核心区域:
当前状态卡片:以全宽渐变卡片展示连接状态、连接类型和所有活跃的网络类型标签。
网络信息卡片:展示监听状态、变化次数、OH 平台适配状态等元信息。
自动刷新设置卡片:提供注册示例刷新任务和手动触发刷新的操作入口。
状态变化历史列表:逆序展示最近的网络状态切换记录,包括切换时间戳、变化方向和描述文字。
页面入口定义在 workspace_page.dart 的工作台网格中,通过 WorkspaceItem 配置路由跳转:
dart
WorkspaceItem(
id: 'connectivity',
title: '网络状态',
description: '网络连接监听与离线提示',
icon: Icons.wifi,
color: Colors.cyan,
route: '/connectivity',
)
路由在 router.dart 中配置:
dart
GoRoute(
path: '/connectivity',
name: 'connectivity',
pageBuilder: (context, state) => OHRouteTransitionPage(
key: state.pageKey,
child: const ConnectivityPage(),
),
)
九、OH 平台权限体系说明
9.1 Flutter 应用层权限模型
connectivity_plus 在 OpenHarmony 平台的网络功能实现依赖于 Flutter 框架层与 OH 原生系统之间的平台通道。平台通道的通信在 OH 系统层面由系统服务管理,应用无需在 module.json5 中额外声明互联网权限------这一点与 Android 平台需要在 AndroidManifest.xml 中声明 ACCESS_NETWORK_STATE 权限形成对比。
Flutter for OpenHarmony 的架构中,网络能力作为基础平台能力默认对应用开放。connectivity_plus 通过 MethodChannel 向原生侧查询网络状态,返回值由 OH 的网络管理子系统提供,该子系统本身是系统级服务,无需应用授权。
9.2 OH 平台适配要点
connectivity_plus 在 OH 平台的表现与 Android 平台高度一致,但在实现机制上存在差异:
监听机制 。Android 平台通过 ConnectivityManager 的 registerNetworkCallback 实现实时监听;iOS 平台通过 Reachability 机制;OpenHarmony 平台则通过 wifi 和 net connection 等系统 API 实现。connectivity_plus 在各平台的适配层屏蔽了这些差异,Flutter 层使用统一的 onConnectivityChanged 流接口。
类型映射 。OH 平台的网络类型返回值定义在 @ohos.net.connection 模块中,其枚举值与 connectivity_plus 的 ConnectivityResult 枚举存在一一对应关系,这一映射在 Dart 层完成,对业务代码透明。
平台检测 。部分场景需要判断当前是否运行在 OH 平台,我们通过 Platform.operatingSystem 属性检测:
dart
bool _isOHEnvironment() {
try {
final os = Platform.operatingSystem.toLowerCase();
return os.contains('harmony') ||
os.contains('openharmony') ||
os.contains('ohos');
} catch (e) {
return false;
}
}
十、工作台集成示例
在 workspace_page.dart 中,网络状态管理已深度集成至工作台页面。主要体现在三个层面:
AppBar 指示器 。工作台页面右上角的 AppBar 区域包含一个 ConnectivityIndicator,实时反映当前网络状态。用户点击指示器后,弹出底部菜单展示详细信息。
横幅提示。当设备处于离线状态时,工作台顶部显示红色横幅,告知用户当前处于离线模式。横幅底部提供"重试"按钮,用户点击后重新检查网络状态。
自动刷新联动 。通过 ref.listen 监听 connectivityProvider 的状态变化,当检测到从离线到联网的切换时,自动调用 _onNetworkRestored 方法,显示恢复通知并触发数据刷新。
dart
void _initConnectivityListener() {
ref.listen<ConnectivityState>(connectivityProvider, (previous, next) {
if (previous != null && !previous.isConnected && next.isConnected) {
_onNetworkRestored();
}
if (previous != null && previous.isConnected && !next.isConnected) {
_onNetworkLost();
}
});
}
十一、验证与测试
11.1 静态分析
在编写过程中,所有代码文件均通过 Dart 静态分析工具检查,无编译错误或严重警告:
bash
flutter analyze lib/models/connectivity_info.dart \
lib/services/connectivity_service.dart \
lib/providers/connectivity_provider.dart \
lib/widgets/connectivity_banner.dart \
lib/pages/connectivity_page.dart
11.2 测试场景矩阵
| 测试场景 | 操作步骤 | 预期结果 |
|---|---|---|
| WiFi 连接检测 | 将设备连接至 WiFi 网络 | AppBar 显示绿色 WiFi 图标,详情显示"已连接 - WiFi" |
| WiFi 断开检测 | 关闭设备的 WiFi 开关 | 顶部出现红色离线横幅,AppBar 图标变为灰色 |
| 移动网络检测 | 关闭 WiFi,仅启用移动数据 | AppBar 显示蓝色移动网络图标 |
| 网络恢复刷新 | 离线状态下重新连接网络 | 出现绿色恢复通知,数据自动刷新 |
| 状态历史记录 | 多次切换网络状态 | 历史列表正确记录每次切换的 timestamp 和类型 |
11.3 鸿蒙设备运行验证
在鸿蒙设备上运行应用后,网络状态监听功能正常触发。AppBar 中的 ConnectivityIndicator 能够正确反映设备的实际网络状态,WiFi 连接时显示绿色图标,离线时显示红色图标并附有文字标签。点击指示器弹出的底部菜单完整展示当前连接类型、历史变化记录和手动刷新操作入口。
这是我的运行截图:

十二、项目文件结构
lib/
├── models/
│ └── connectivity_info.dart # 连接类型枚举、网络状态数据模型、
│ # 变化历史记录模型
├── services/
│ └── connectivity_service.dart # 网络状态服务:监听、查询、回调管理
├── providers/
│ └── connectivity_provider.dart # Riverpod Notifier、便捷 Provider、
│ # 自动刷新管理器
├── widgets/
│ └── connectivity_banner.dart # 网络状态横幅、指示器、对话框、
│ # NetworkAwareFutureBuilder
├── pages/
│ ├── connectivity_page.dart # 独立网络状态管理页面
│ └── workspace_page.dart # 工作台页面(已集成网络状态监听)
└── routing/
└── router.dart # go_router 路由配置(/connectivity 路由)
pubspec.yaml # 依赖声明:connectivity_plus ^6.0.3
十三、总结
本文围绕 connectivity_plus 在 Flutter for OpenHarmony 项目中的集成与适配,构建了一套从底层服务到上层 UI 的完整网络状态管理体系。核心技术要点可归纳为以下五个方面:
connectivity_plus 的 OH 平台适配:通过统一的 Dart API 接口屏蔽底层平台差异,实现 WiFi、移动网络、以太网、蓝牙等多种网络类型的监听能力,OH 平台无需额外权限配置。
数据模型与类型映射 :设计了 ConnectionType 枚举、ConnectivityInfo 数据模型和 ConnectivityHistoryEntry 历史记录模型,将原始的 connectivity_plus 结果转换为面向业务的语义化数据结构。
Riverpod 状态管理整合 :通过 ConnectivityNotifier 将网络状态接入 Riverpod 体系,并衍生出 isConnectedProvider、isWifiProvider 等多个便捷 Provider,简化页面层代码。
网络恢复自动刷新 :通过 NetworkRefreshManagerNotifier 实现注册式自动刷新机制,网络恢复时无需用户手动操作,应用自动触发已注册的数据刷新任务。
完整的离线提示 UI :提供了 ConnectivityBanner 横幅组件、ConnectivityIndicator 状态指示器、OfflinePromptDialog 对话框和 NetworkAwareFutureBuilder 异步封装,覆盖了从即时提示到页面级状态展示的完整 UI 需求。
本方案已在实际 OpenHarmony 设备上验证通过,网络状态监听、网络恢复自动刷新、离线提示等核心功能运行稳定。