Flutter for OpenHarmony三方库适配实战:connectivity_plus 网络连接状态
网络连接状态检测是移动应用开发中的基础需求,应用需要根据网络状态来优化数据加载策略、提示用户网络异常或切换离线模式。在 Flutter for OpenHarmony 应用开发中,是一个功能完善的网络连接状态检测插件,提供了跨平台的网络状态获取能力。connectivity_plus 库为 Flutter for OpenHarmony 开发提供了完整的网络连接状态检测能力。通过简洁的 API,开
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
本文基于flutter3.27.5开发

一、connectivity_plus 库概述
网络连接状态检测是移动应用开发中的基础需求,应用需要根据网络状态来优化数据加载策略、提示用户网络异常或切换离线模式。在 Flutter for OpenHarmony 应用开发中,connectivity_plus 是一个功能完善的网络连接状态检测插件,提供了跨平台的网络状态获取能力。
connectivity_plus 库特点
connectivity_plus 库基于 Flutter 平台接口实现,提供了以下核心特性:
网络状态检测:支持检测当前设备的网络连接状态,区分 WiFi、蜂窝网络、以太网、蓝牙等多种连接类型。
实时状态监听:提供 Stream 接口,实时监听网络状态变化,无需轮询,性能更优。
多网络类型支持:支持检测 WiFi、蜂窝网络(mobile)、以太网(ethernet)、蓝牙(bluetooth)、VPN 等多种网络类型。
跨平台统一 API:提供统一的 Dart API,开发者无需关心底层平台差异,一套代码多端运行。
轻量级设计:插件体积小,性能开销低,适合各种规模的应用。
功能支持对比
| 功能 | Android | iOS | OpenHarmony |
|---|---|---|---|
| 检测网络状态 | ✅ | ✅ | ✅ |
| 区分网络类型 | ✅ | ✅ | ✅ |
| 网络状态变化监听 | ✅ | ✅ | ✅ |
| VPN 检测 | ✅ | ⚠️ | ✅ |
| 蓝牙网络检测 | ✅ | ✅ | ✅ |
注意:iOS/macOS 平台 VPN 连接返回
other,OpenHarmony 平台可以正确识别 VPN 连接。
使用场景:网络状态监控、离线模式切换、网络类型判断、网络异常提示、数据加载策略优化等。
二、安装与配置
2.1 添加依赖
在项目的 pubspec.yaml 文件中添加 connectivity_plus 依赖:
dependencies:
connectivity_plus:
git:
url: https://atomgit.com/openharmony-sig/flutter_plus_plugins.git
path: packages/connectivity_plus/connectivity_plus
然后执行以下命令获取依赖:
flutter pub get
2.2 兼容性信息
| 项目 | 版本要求 |
|---|---|
| Flutter SDK | 3.7.12-ohos-1.0.6 |
| OpenHarmony SDK | 5.0.0 (API 12) |
| DevEco Studio | 5.0.13.200 |
| ROM | 5.1.0.120 SP3 |
2.3 权限配置
connectivity_plus 在 OpenHarmony 平台上需要配置网络权限。在 ohos/entry/src/main/module.json5 文件中添加:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
注意:只需要
ohos.permission.INTERNET权限即可,不需要额外的网络状态权限。
三、核心 API 详解
3.1 Connectivity 类
Connectivity 是 connectivity_plus 库的核心类,采用单例模式设计,提供网络状态检测的所有方法。
class Connectivity {
factory Connectivity();
Future<ConnectivityResult> checkConnectivity();
Stream<ConnectivityResult> get onConnectivityChanged;
}
使用示例:
final connectivity = Connectivity();
3.2 checkConnectivity 方法
checkConnectivity 方法用于检查当前网络连接状态。
Future<ConnectivityResult> checkConnectivity()
返回值:返回 ConnectivityResult 枚举值,表示当前网络连接类型。
使用示例:
final connectivity = Connectivity();
final result = await connectivity.checkConnectivity();
if (result == ConnectivityResult.mobile) {
print('连接到蜂窝网络');
} else if (result == ConnectivityResult.wifi) {
print('连接到 WiFi 网络');
} else if (result == ConnectivityResult.ethernet) {
print('连接到以太网');
} else if (result == ConnectivityResult.bluetooth) {
print('连接到蓝牙网络');
} else if (result == ConnectivityResult.vpn) {
print('连接到 VPN');
} else if (result == ConnectivityResult.other) {
print('连接到其他网络');
} else if (result == ConnectivityResult.none) {
print('无网络连接');
}
3.3 onConnectivityChanged 属性
onConnectivityChanged 属性是一个 Stream,用于监听网络状态变化。
Stream<ConnectivityResult> get onConnectivityChanged
返回值:返回 ConnectivityResult 的 Stream,每次网络状态变化时触发。
使用示例:
final connectivity = Connectivity();
StreamSubscription<ConnectivityResult> subscription;
void initState() {
super.initState();
subscription = connectivity.onConnectivityChanged.listen((ConnectivityResult result) {
print('网络状态变化: $result');
if (result == ConnectivityResult.none) {
_showNetworkError();
}
});
}
void dispose() {
subscription.cancel();
super.dispose();
}
3.4 ConnectivityResult 枚举
ConnectivityResult 枚举定义了所有可能的网络连接类型。
enum ConnectivityResult {
bluetooth,
wifi,
ethernet,
mobile,
none,
vpn,
other,
}
枚举值说明:
| 枚举值 | 说明 | OpenHarmony 支持 |
|---|---|---|
| bluetooth | 通过蓝牙连接的设备 | ✅ |
| wifi | 通过 WiFi 连接的设备 | ✅ |
| ethernet | 连接到以太网的设备 | ✅ |
| mobile | 连接到蜂窝网络的设备 | ✅ |
| none | 未连接到任何网络 | ✅ |
| vpn | 连接到 VPN 的设备 | ✅ |
| other | 连接到未知网络 | ✅ |
四、OpenHarmony 平台实现原理
4.1 原生 API 映射
connectivity_plus 在 OpenHarmony 平台上使用 @ohos.net.connection 模块实现:
| Flutter API | OpenHarmony API |
|---|---|
| checkConnectivity() | connection.getDefaultNet() |
| connection.getNetCapabilities() | |
| onConnectivityChanged | connection.createNetConnection() |
4.2 网络类型映射
OpenHarmony 的 NetBearType 与 Flutter 的 ConnectivityResult 映射关系:
| OpenHarmony 状态 | Flutter 状态 |
|---|---|
| BEARER_WIFI | wifi |
| BEARER_CELLULAR | mobile |
| BEARER_ETHERNET | ethernet |
| netId == 0 | none |
| 其他 | none |
4.3 实现原理
OpenHarmony 平台通过以下步骤实现网络状态检测:
1. 获取默认网络句柄:
const netHandle = await connection.getDefaultNet();
if (netHandle.netId == 0) {
return Connectivity.CONNECTIVITY_NONE;
}
2. 获取网络能力信息:
const capabilities = await connection.getNetCapabilities(netHandle);
this.networkType = this.hasTransport(capabilities.bearerTypes);
3. 判断网络类型:
hasTransport(capabilities: Array<number>): String {
if (capabilities.includes(connection.NetBearType.BEARER_WIFI)) {
return Connectivity.CONNECTIVITY_WIFI;
}
if (capabilities.includes(connection.NetBearType.BEARER_ETHERNET)) {
return Connectivity.CONNECTIVITY_ETHERNET;
}
if (capabilities.includes(connection.NetBearType.BEARER_CELLULAR)) {
return Connectivity.CONNECTIVITY_MOBILE;
}
return Connectivity.CONNECTIVITY_NONE;
}
4. 网络状态监听:
通过 connection.createNetConnection() 创建网络连接对象,监听网络状态变化事件。
五、实战案例
5.1 检查网络状态
Future<void> checkNetworkStatus() async {
final connectivity = Connectivity();
final result = await connectivity.checkConnectivity();
switch (result) {
case ConnectivityResult.mobile:
print('使用蜂窝网络');
break;
case ConnectivityResult.wifi:
print('使用 WiFi 网络');
break;
case ConnectivityResult.ethernet:
print('使用以太网');
break;
case ConnectivityResult.none:
print('无网络连接');
break;
default:
print('其他网络类型');
}
}
5.2 监听网络状态变化
StreamSubscription<ConnectivityResult>? _subscription;
void startNetworkListener() {
final connectivity = Connectivity();
_subscription = connectivity.onConnectivityChanged.listen((result) {
if (result == ConnectivityResult.none) {
print('网络已断开');
} else {
print('网络已连接: $result');
}
});
}
void stopNetworkListener() {
_subscription?.cancel();
_subscription = null;
}
5.3 判断是否有网络连接
Future<bool> hasNetworkConnection() async {
final connectivity = Connectivity();
final result = await connectivity.checkConnectivity();
return result != ConnectivityResult.none;
}
5.4 根据网络类型优化加载策略
Future<void> loadData() async {
final connectivity = Connectivity();
final result = await connectivity.checkConnectivity();
if (result == ConnectivityResult.wifi) {
print('WiFi 环境,加载高清图片');
} else if (result == ConnectivityResult.mobile) {
print('蜂窝网络,加载标清图片');
} else if (result == ConnectivityResult.none) {
print('无网络,显示缓存数据');
}
}
5.5 完整的网络状态监控组件
class NetworkMonitor extends StatefulWidget {
const NetworkMonitor({super.key});
State<NetworkMonitor> createState() => _NetworkMonitorState();
}
class _NetworkMonitorState extends State<NetworkMonitor> {
final Connectivity _connectivity = Connectivity();
ConnectivityResult _connectionStatus = ConnectivityResult.none;
StreamSubscription<ConnectivityResult>? _subscription;
List<String> _statusHistory = [];
void initState() {
super.initState();
_initConnectivity();
_listenConnectivity();
}
Future<void> _initConnectivity() async {
try {
final result = await _connectivity.checkConnectivity();
setState(() {
_connectionStatus = result;
});
} catch (e) {
print('初始化网络状态失败: $e');
}
}
void _listenConnectivity() {
_subscription = _connectivity.onConnectivityChanged.listen((result) {
setState(() {
_connectionStatus = result;
_statusHistory.insert(0, '${DateTime.now().toString().substring(11, 19)} - ${_getStatusText(result)}');
if (_statusHistory.length > 10) {
_statusHistory.removeLast();
}
});
});
}
String _getStatusText(ConnectivityResult result) {
switch (result) {
case ConnectivityResult.mobile:
return '蜂窝网络';
case ConnectivityResult.wifi:
return 'WiFi 网络';
case ConnectivityResult.ethernet:
return '以太网';
case ConnectivityResult.bluetooth:
return '蓝牙网络';
case ConnectivityResult.vpn:
return 'VPN 网络';
case ConnectivityResult.other:
return '其他网络';
case ConnectivityResult.none:
return '无网络连接';
}
}
void dispose() {
_subscription?.cancel();
super.dispose();
}
Widget build(BuildContext context) {
return Column(
children: [
Text('当前网络: ${_getStatusText(_connectionStatus)}'),
Text('状态历史: ${_statusHistory.length} 条记录'),
],
);
}
}
六、最佳实践
6.1 及时取消监听
监听网络状态变化时,务必在组件销毁时取消订阅:
void dispose() {
_subscription?.cancel();
super.dispose();
}
6.2 错误处理
对网络状态获取进行错误处理:
Future<void> safeCheckConnectivity() async {
try {
final connectivity = Connectivity();
final result = await connectivity.checkConnectivity();
print('网络状态: $result');
} on PlatformException catch (e) {
print('获取网络状态失败: ${e.message}');
}
}
6.3 性能优化建议
使用 Stream 监听而不是轮询:
// 不推荐:频繁轮询
Timer.periodic(Duration(seconds: 1), (_) async {
final result = await connectivity.checkConnectivity();
});
// 推荐:使用 Stream 监听
connectivity.onConnectivityChanged.listen((result) {
// 自动响应状态变化
});
6.4 应用恢复时检查
Android 8.0+ 后台无法接收网络状态变化,建议在应用恢复时主动检查:
class _MyWidgetState extends State<MyWidget> with WidgetsBindingObserver {
final Connectivity _connectivity = Connectivity();
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_checkConnectivity();
}
}
Future<void> _checkConnectivity() async {
final result = await _connectivity.checkConnectivity();
print('网络状态: $result');
}
}
七、常见问题
Q1:为什么网络状态显示 WiFi 但无法访问互联网?
connectivity_plus 只能检测设备的网络连接状态,不能保证能够访问互联网。例如,设备可能连接到 WiFi,但该 WiFi 没有互联网访问权限。
解决方案:建议在实际网络请求时进行超时和错误处理:
try {
final response = await http.get(Uri.parse('https://example.com'))
.timeout(const Duration(seconds: 10));
} catch (e) {
print('网络请求失败: $e');
}
Q3:如何区分 WiFi 和移动热点?
connectivity_plus 无法区分 WiFi 和移动热点。如果需要区分,可以尝试连接特定服务器并检查响应,或者使用其他网络信息插件。
Q4:VPN 连接在 iOS/macOS 上返回 other?
是的,iOS 和 macOS 没有单独的 VPN 网络接口类型,会返回 ConnectivityResult.other。在 OpenHarmony 上,VPN 连接会正确返回 ConnectivityResult.vpn。
Q5:Web 平台支持情况如何?
Web 平台依赖浏览器的 NetworkInformation API,功能受限,只能检测在线/离线状态,部分浏览器可能不支持。
八、总结
connectivity_plus 库为 Flutter for OpenHarmony 开发提供了完整的网络连接状态检测能力。通过简洁的 API,开发者可以轻松检测网络状态并监听网络变化,为应用提供更好的网络体验。该库在鸿蒙平台上已经完成了完整的适配,支持所有核心功能,开发者可以放心使用。
九、完整代码示例
以下是一个完整的可运行示例,展示了 connectivity_plus 库的核心功能:
main.dart
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Connectivity Plus Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final Connectivity _connectivity = Connectivity();
ConnectivityResult _connectionStatus = ConnectivityResult.none;
StreamSubscription<ConnectivityResult>? _subscription;
List<String> _statusHistory = [];
void initState() {
super.initState();
_initConnectivity();
_listenConnectivity();
}
Future<void> _initConnectivity() async {
try {
final result = await _connectivity.checkConnectivity();
setState(() {
_connectionStatus = result;
});
} on PlatformException catch (e) {
_showMessage('获取网络状态失败: ${e.message}');
}
}
void _listenConnectivity() {
_subscription = _connectivity.onConnectivityChanged.listen((result) {
setState(() {
_connectionStatus = result;
_statusHistory.insert(
0,
'${DateTime.now().toString().substring(11, 19)} - ${_getStatusText(result)}',
);
if (_statusHistory.length > 10) {
_statusHistory.removeLast();
}
});
});
}
void _showMessage(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
void dispose() {
_subscription?.cancel();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Connectivity Plus 演示'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'网络连接状态',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Icon(
_getStatusIcon(),
size: 80,
color: _getStatusColor(),
),
const SizedBox(height: 16),
Text(
_getStatusText(_connectionStatus),
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: _getStatusColor(),
),
),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'网络详情',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const Divider(),
_buildInfoRow('连接类型', _getStatusText(_connectionStatus)),
_buildInfoRow('网络可用', _connectionStatus != ConnectivityResult.none ? '是' : '否'),
_buildInfoRow('WiFi 连接', _connectionStatus == ConnectivityResult.wifi ? '是' : '否'),
_buildInfoRow('蜂窝网络', _connectionStatus == ConnectivityResult.mobile ? '是' : '否'),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'状态变化历史',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
TextButton(
onPressed: () {
setState(() {
_statusHistory.clear();
});
},
child: const Text('清空'),
),
],
),
const Divider(),
if (_statusHistory.isEmpty)
const Text('暂无状态变化记录')
else
Column(
children: _statusHistory.map((record) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Text(record),
);
}).toList(),
),
],
),
),
),
const SizedBox(height: 16),
ElevatedButton.icon(
onPressed: _initConnectivity,
icon: const Icon(Icons.refresh),
label: const Text('刷新网络状态'),
),
],
),
),
);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(color: Colors.grey)),
Text(value, style: const TextStyle(fontWeight: FontWeight.bold)),
],
),
);
}
String _getStatusText(ConnectivityResult result) {
switch (result) {
case ConnectivityResult.mobile:
return '蜂窝网络';
case ConnectivityResult.wifi:
return 'WiFi 网络';
case ConnectivityResult.ethernet:
return '以太网';
case ConnectivityResult.bluetooth:
return '蓝牙网络';
case ConnectivityResult.vpn:
return 'VPN 网络';
case ConnectivityResult.other:
return '其他网络';
case ConnectivityResult.none:
return '无网络连接';
}
}
IconData _getStatusIcon() {
switch (_connectionStatus) {
case ConnectivityResult.mobile:
return Icons.signal_cellular_4_bar;
case ConnectivityResult.wifi:
return Icons.wifi;
case ConnectivityResult.ethernet:
return Icons.cable;
case ConnectivityResult.bluetooth:
return Icons.bluetooth;
case ConnectivityResult.vpn:
return Icons.vpn_key;
case ConnectivityResult.other:
return Icons.network_check;
case ConnectivityResult.none:
return Icons.signal_wifi_off;
}
}
Color _getStatusColor() {
return _connectionStatus == ConnectivityResult.none ? Colors.red : Colors.green;
}
}
十、参考资源
更多推荐


所有评论(0)