Flutter for OpenHarmony:universal_io 屏蔽多端差异,实现文件与网络操作的大一统(跨平台标准 IO 库) 深度解析与鸿蒙适配指南
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net

前言
在 Flutter 开发中,dart:io 是我们处理文件、网络和 Socket 等底层操作的核心库。然而,当我们的应用需要同时运行在移动端(Android/iOS/OpenHarmony)、Web 端以及桌面端时,直接使用 dart:io 往往会遇到兼容性问题,因为 Web 端并不支持 dart:io。
这时,universal_io 就派上用场了。它提供了一套与 dart:io 几乎完全一致的 API,但底层自动处理了平台差异,使得同一套代码可以在所有平台上运行,包括 OpenHarmony。本文将详细介绍如何在 OpenHarmony 项目中使用 universal_io,并提供实战示例。
一、universal_io 简介
1.1 什么是 universal_io?
universal_io 是一个旨在解决跨平台 IO 操作痛点的库。它允许开发者编写仅依赖 universal_io 的代码,而无需在代码中通过 if (kIsWeb) 来区分 Web 和 Native 环境。
1.2 为什么在 OpenHarmony 上使用?
虽然 OpenHarmony 支持标准的 dart:io,但在构建跨平台应用(不仅仅是 OpenHarmony,还包括 Web 或其它嵌入式平台)时,使用 universal_io 可以保持代码的一致性和可维护性。它能确保你的 IO 逻辑在 OpenHarmony 设备上表现得像在 Android 或 iOS 上一样稳定。
引入
平台检测
Web
移动/桌面
OpenHarmony
Flutter 应用代码
universal_io
运行环境
浏览器 API (dart:html)
原生 API (dart:io)
统一输出结果
二、核心 API 详解与示例
在使用前,请确保在 pubspec.yaml 中添加依赖:
dependencies:flutter:sdk: flutter universal_io: ^2.3.1 2.1 示例一:跨平台获取操作系统信息
在不同平台上获取操作系统名称通常需要条件判断,使用 universal_io 的 Platform 类可以简化这一过程。
import'package:flutter/material.dart';import'package:universal_io/io.dart';// 引入 universal_iovoidcheckPlatform(){// ✅ 推荐:直接使用 Platform 类,它会自动适配 Web 和 NativeString os =Platform.operatingSystem;String version =Platform.operatingSystemVersion;print('当前操作系统: $os');print('系统版本: $version');if(Platform.isAndroid){print('这是 Android 设备');}elseif(Platform.isIOS){print('这是 iOS 设备');}elseif(Platform.isFuchsia){// OpenHarmony 在某些检测中可能表现特定,建议结合设备实测print('这是 Fuchsia/OpenHarmony 设备');}}
2.2 示例二:跨平台文件读写
在 OpenHarmony 上进行文件读写,路径管理非常重要。universal_io 的 File 类与 dart:io 用法一致。
import'package:universal_io/io.dart';import'dart:convert';Future<void>writeAndReadFile(String path)async{final file =File(path);// 1. 写入内容// 💡 技巧:使用 UTF-8 编码避免乱码await file.writeAsString('Hello OpenHarmony via universal_io!', encoding: utf8);print('文件写入成功');// 2. 读取内容if(await file.exists()){String content =await file.readAsString();print('读取到的内容: $content');}else{print('⚠️ 注意:文件不存在');}}
2.3 示例三:跨平台 HTTP 请求
虽然 dio 很强大,但有时我们只需要简单的 HttpClient。universal_io 提供了跨平台的 HttpClient 实现。
import'package:universal_io/io.dart';import'dart:convert';Future<void>fetchUrl(String url)async{final client =HttpClient();try{// ✅ 推荐:支持链式调用final request =await client.getUrl(Uri.parse(url));final response =await request.close();// 处理响应流final body =await response.transform(utf8.decoder).join();print('响应状态码: ${response.statusCode}');print('响应内容长度: ${body.length}');}catch(e){print('❌ 错误:请求失败 - $e');}finally{ client.close();// 记得关闭客户端}}
三、OpenHarmony 平台适配
3.1 路径获取策略
在 OpenHarmony 上,我们通常需要结合 path_provider 来获取正确的应用沙箱路径,然后再使用 universal_io 进行操作。
// 需要配合 path_provider 使用// import 'package:path_provider/path_provider.dart';// Directory appDocDir = await getApplicationDocumentsDirectory();// String appDocPath = appDocDir.path;// File file = File('$appDocPath/my_file.txt');3.2 网络权限
在 OpenHarmony (config.json 或 module.json5) 中,务必声明网络权限,否则 HttpClient 将无法工作。
"requestPermissions":[{"name":"ohos.permission.INTERNET"}]四、完整实战示例:简易网络检测与日志记录器
本示例展示如何在 OpenHarmony 上创建一个应用,它能检测网络连通性并将日志写入本地文件。
4.1 示例代码
import'package:flutter/material.dart';import'package:universal_io/io.dart';import'package:path_provider/path_provider.dart';// 需添加此依赖import'dart:convert';voidmain(){runApp(constMyApp());}classMyAppextendsStatelessWidget{constMyApp({super.key});@overrideWidgetbuild(BuildContext context){returnMaterialApp( home:Scaffold( appBar:AppBar(title:constText('Universal IO 实战')), body:constNetworkLoggerPage(),),);}}classNetworkLoggerPageextendsStatefulWidget{constNetworkLoggerPage({super.key});@overrideState<NetworkLoggerPage>createState()=>_NetworkLoggerPageState();}class _NetworkLoggerPageState extendsState<NetworkLoggerPage>{String _logContent ='等待操作...'; bool _isLoading =false;// 获取日志文件路径Future<File>_getLogFile()async{final directory =awaitgetApplicationDocumentsDirectory();returnFile('${directory.path}/network_log.txt');}// 执行网络检测并记录Future<void>_checkAndLog()async{setState(()=> _isLoading =true);final client =HttpClient();String result ='';try{// 1. 发起请求final request =await client.getUrl(Uri.parse('https://www.baidu.com'));final response =await request.close(); result ='${DateTime.now()}: 请求成功, 状态码 ${response.statusCode}\n';}catch(e){ result ='${DateTime.now()}: 请求失败, 错误 $e\n';}finally{ client.close();}// 2. 写入文件try{final file =await_getLogFile();// 使用 append 模式追加内容await file.writeAsString(result, mode:FileMode.append, flush:true);// 3. 读取最新日志_refreshLogs();}catch(e){setState(()=> _logContent ='写入日志失败: $e');}setState(()=> _isLoading =false);}// 读取日志显示Future<void>_refreshLogs()async{try{final file =await_getLogFile();if(await file.exists()){String content =await file.readAsString();setState(()=> _logContent = content);}else{setState(()=> _logContent ='日志文件不存在');}}catch(e){setState(()=> _logContent ='读取日志失败: $e');}}// 清除日志Future<void>_clearLogs()async{final file =await_getLogFile();if(await file.exists()){await file.delete();_refreshLogs();}}@overrideWidgetbuild(BuildContext context){returnPadding( padding:constEdgeInsets.all(16.0), child:Column( crossAxisAlignment:CrossAxisAlignment.stretch, children:[Row( mainAxisAlignment:MainAxisAlignment.spaceEvenly, children:[ElevatedButton.icon( icon:constIcon(Icons.network_check), label:constText('检测网络并记录'), onPressed: _isLoading ?null: _checkAndLog,),ElevatedButton.icon( icon:constIcon(Icons.delete), label:constText('清除日志'), onPressed: _isLoading ?null: _clearLogs, style:ElevatedButton.styleFrom(backgroundColor:Colors.red[100]),),],),constSizedBox(height:20),constText('日志内容:', style:TextStyle(fontWeight:FontWeight.bold)),constSizedBox(height:10),Expanded( child:Container( padding:constEdgeInsets.all(8), decoration:BoxDecoration( border:Border.all(color:Colors.grey), borderRadius:BorderRadius.circular(4), color:Colors.grey[100],), child:SingleChildScrollView( child:Text(_logContent),),),),],),);}}
五、总结
universal_io 为 Flutter 应用提供了一致且强大的 IO 操作能力。在 OpenHarmony 开发中,它能帮助我们将现有的 Dart IO 代码无缝迁移,同时保留了跨平台到 Web 的可能性。
最佳实践:
- 始终优先使用
universal_io替代dart:io,以备未来跨平台需求。 - 在 OpenHarmony 上操作文件时,务必结合
path_provider获取合法路径。 - 网络请求需配置相应的权限。