☰
OpenHarmony + Flutter + Dio 跨平台数据清单应用实战
2026/10/22 7:57:55 网站建设 项目流程

从零开始接 OpenHarmony 的项目,最头疼的往往不是系统本身,而是“应用怎么落地”。开源鸿蒙这几年的生态越走越实,但实际开发时,大家还是会纠结:要不要直接上 ArkUI?能不能复用已有的 Flutter 代码?网络层用什么?带着这些疑问,我全程跟完了某开源鸿蒙跨平台训练营的 DAY3,这一期主题非常硬核——HarmonyOS + Flutter + Dio 三者组合,从零实现一个跨平台数据清单应用。今天的文章不写理论,直接把我实操过程中踩过的坑、调通的代码、验证过的方案全部记录下来,给同样在搞 OpenHarmony 应用开发的朋友做个参考。

先说结论:这个组合完全可行,而且比想象中稳。Flutter 负责 UI 和业务逻辑,Dio 负责网络请求,OpenHarmony 作为底层系统承载应用运行,三者各司其职。整个项目跑下来的体验是:Flutter 代码几乎可以原样复用,Dio 的适配层只需要处理平台通道,剩下的工作量基本集中在 ArkUI 和 Flutter 的通信桥接上。如果你是 Flutter 老手,这套路子上手非常快;如果你是从零开始接触鸿蒙开发,跟着这篇文章走一遍,也能对 OpenHarmony 的跨平台开发模型有一个完整认知。

1. 项目背景与方案选型

1.1 为什么选 Flutter + Dio 而不是纯 ArkUI 开发

做 OpenHarmony 应用,摆在前面的路其实有好几条:纯 ArkUI 声明式开发、基于方舟编译器的原生 App、或者采用跨平台框架。纯 ArkUI 的优点在于系统深度集成,性能无可挑剔,但它的问题是学习成本高,而且已有的业务代码没法复用,对于已经有 Flutter/React Native 存量项目的团队来说,迁移代价非常大。

Flutter 的跨平台模型是自带渲染引擎的,UI 层不依赖系统原生组件,这意味着在 OpenHarmony 上跑 Flutter,理论上 UI 一致性和性能表现都会比较稳定。更重要的是,Flutter 的生态非常成熟,状态管理、路由、网络请求、本地存储这些配套方案都很完善。Dio 作为 Flutter 生态里使用率最高的网络库,API 设计简洁,支持拦截器、请求取消、文件上传下载、表单提交等常用功能,在 OpenHarmony 场景下只需要解决底层适配问题,上层的业务代码和 Android/iOS 完全通用。

从训练营的教学设计来看,选择 Flutter + Dio 还有一个现实考量:跨平台数据清单应用这个题目,重点在于“数据流转”,从 UI 事件触发网络请求、到数据解析、再到列表渲染,这个链路在 Flutter 下可以用最少的代码实现,而且错误处理、加载状态这些逻辑写起来非常直观。纯 ArkUI 写当然也可以,但代码量和学习曲线都会陡一些,用在一天的训练营里不太合适。

1.2 OpenHarmony 跨平台开发的整体架构

要理解 HarmonyOS + Flutter + Dio 这套组合,首先要搞清楚 OpenHarmony 应用侧的几个基本概念。OpenHarmony 的应用模型基于 Stage 模型,一个应用由一个或多个 Ability 组成,UIAbility 负责提供界面,应用通过 module.json5 声明权限和组件。Flutter 应用跑在 OpenHarmony 上,本质上是通过一个原生的 UIAbility 作为宿主容器,Flutter engine 作为一个独立的渲染引擎运行在这个容器之上。

整个架构可以用一句话概括:开一个原生窗口,让 Flutter 的内容渲染进去,然后通过网络请求获取数据,最终把数据渲染到 Flutter 的 Widget 树里。Dio 的网络请求在 Flutter 引擎内部发起,通过 Dart 的 IO 能力直接走 socket 通信,不需要经过 ArkUI 层。但需要注意的是,OpenHarmony 对网络权限有明确要求,必须在 module.json5 里声明 ohos.permission.INTERNET,否则请求会静默失败。

这个架构的好处在于,跨平台能力真正落地了:同样的 Dart 代码,在 Android、iOS、OpenHarmony 上行为一致,Dio 的 API 也是同一套。需要额外处理的只有两个点:一是 Flutter 引擎如何集成进 OpenHarmony 应用,二是原生的系统能力(比如获取设备信息、调用系统 API)如何通过平台通道暴露给 Flutter。理解了这个模型,后面所有代码都能顺理成章地写出来。

2. 环境搭建与工程结构设计

2.1 基础环境准备:DevEco Studio 与 Flutter SDK

这次实操使用的是某高校实验室预配的环境,但整体步骤和标准流程一致。要跑通这个项目,需要准备的环境有:

组件版本要求说明
OpenHarmony SDK4.0 及以上建议用 4.1,API 更稳定
Flutter SDK3.7 以上需要使用支持 OpenHarmony 的分支
Dio5.x训练营使用 5.3.2 版本
DevEco Studio4.0 及以上创建和构建 OpenHarmony 工程

需要注意的坑:OpenHarmony 官方推荐的 Flutter SDK 不是 flutter 官方主线,而是基于社区维护的 flutter_ohos 分支。如果直接拿官方 Flutter SDK 来跑,构建时会提示找不到 OpenHarmony 平台支持。安装 Flutter SDK 时确保环境变量指向支持 OpenHarmony 的分支,然后跑 flutter doctor 确认没有问题。

DevEco Studio 是 OpenHarmony 应用开发的主 IDE,它负责生成应用工程结构、编译 HAP 包。这里有个细节:OpenHarmony 的应用最终打包成 HAP 格式,而 Flutter 的产物是 so 库和资源文件的组合,两者需要通过集成模板合并。训练营给的方法是,先用 Flutter 生成产物,再把产物拷入 OpenHarmony 工程的对应目录,最后由 DevEco Studio 统一打包。这样做的好处是不用改 Flutter 的构建流程,减少出错面。

2.2 工程目录结构与模块划分

整个项目我在实操中按功能拆成了三个模块,目录划分直接影响到后续协作和排错效率:

project_root ├── flutter_module # Flutter 业务层 │ ├── lib │ │ ├── main.dart # 入口文件 │ │ ├── models/ # 数据模型 │ │ ├── services/ # Dio 网络请求封装 │ │ ├── pages/ # 页面 UI │ │ └── utils/ # 工具函数 │ └── pubspec.yaml ├── ohos_app # OpenHarmony 工程 │ ├── entry/src/main │ │ ├── module.json5 │ │ └── ets/ # 原生加载 Flutter 的入口代码 │ └── build-profile.json5 └── integration # 构建集成脚本

这个结构的核心思想是:Flutter 工程保持独立,OpenHarmony 工程只是承载壳子,两者通过产物文件交互。这样 Flutter 部分的代码可以很方便地移植到其他平台,同时 OpenHarmony 工程的管理复杂度也降到了最低。我在实操后发现,把 integration 脚本单独放一层非常有用,后续自动构建 CI 都可以复用。

Flutter 模块里的 pages 目录是真正的业务展示层,包含清单页面、详情页面和错误页面;services 目录里的 dio_client.dart 集中配置 Dio 实例。这样设计的理由很简单:网络层和 UI 层解耦,后面对接不同的后端接口只需要改 services 层,完全不影响 UI。

2.3 module.json5 权限配置与基础参数

OpenHarmony 工程的配置文件 module.json5 是整个应用能否正常运行的关键,这里列举训练营实操时最终确定的配置项:

{ "module": { "name": "entry", "type": "entry", "requestPermissions": [ { "name": "ohos.permission.INTERNET" } ], "abilities": [ { "name": "EntryAbility", "type": "page", "exported": true, "skills": [ { "entities": ["entity.system.home"] } ] } ] } }

活动内容里最关键的是 requestPermissions 数组。没有 INTERNET 权限,Dio 请求发出去之后只会得到一个 SocketException,排查半天也找不到原因。这块是训练营里占时间最多的排错点之一,很多同学都是查了网络层、查了代码,结果发现是权限没配。

另外一个容易忽略的配置是签名。DevEco Studio 创建工程时默认用的是自动签名模式,如果你没有配置好签名,应用装不上真机。训练营里用模拟器的时候没问题,但转换到真机上就卡住了。所以在开始写代码之前,先把自动签名跑通,省得后面为这些环境问题浪费时间。

3. Dio 网络层搭建与数据模型设计

3.1 Dio 实例封装与拦截器设计

数据清单应用的核心是网络请求。我用 Dio 5.3.2,实例化时做了三层封装:基础配置、拦截器、错误处理。先看代码:

import 'package:dio/dio.dart'; class DioClient { static final DioClient _instance = DioClient._internal(); late final Dio dio; DioClient._internal() { dio = Dio(BaseOptions( baseUrl: 'https://api.example.com', connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 10), responseType: ResponseType.json, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, )); dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { // 统一添加 token 或者签名 options.headers['timestamp'] = DateTime.now().millisecondsSinceEpoch.toString(); handler.next(options); }, onResponse: (response, handler) { // 统一校验业务状态码 final code = response.data['code']; if (code != 0) { handler.reject(DioException( requestOptions: response.requestOptions, message: response.data['message'], )); } handler.next(response); }, onError: (DioException e, handler) { // 统一错误转换 handler.next(e); }, )); } factory DioClient() => _instance; Future<List<dynamic>> fetchList(String path) async { try { final response = await dio.get(path); return response.data['data'] as List; } on DioException catch (e) { throw ApiException(e.message ?? 'network error'); } } }

这段代码有几个设计点值得细说。单例模式避免每次请求都重建 Dio 实例,连接池和底层 socket 可以被复用,性能上有明显的收益。BaseOptions 里的 connectTimeout 设置 10 秒,在弱网环境下的容错性更好,避免长时间卡住用户界面。

拦截器是 Dio 的核心特性,可以类比为快递公司的中转站,每个包裹(请求/响应)都要经过这个中转站做统一处理。上面代码中 onRequest 拦截器给每个请求自动添加 timestamp 头,用于服务端做请求时间校验;onResponse 拦截器则统一校验业务状态码,把后端约定的 code 非 0 场景提前转化为异常,上层调用不需要每个接口都写一遍判断逻辑。

我把 fetchList 方法直接放在 DioClient 里,返回原始 List 类型,具体的数据转换交给数据层做。这个分层的好处是,如果后端数据结构调整,只需要改数据层,网络层完全不需要动。

3.2 数据模型定义与 JSON 解析

清单应用的核心数据模型是 Item,训练营场景下这个模型包含 id、名称、描述、状态、创建时间等字段。定义如下:

class Item { final int id; final String title; final String description; final int status; final String createdAt; Item({ required this.id, required this.title, required this.description, required this.status, required this.createdAt, }); factory Item.fromJson(Map<String, dynamic> json) { return Item( id: json['id'] as int, title: json['title'] as String, description: json['description'] ?? '', status: json['status'] as int, createdAt: json['createdAt'] as String, ); } Map<String, dynamic> toJson() { return { 'id': id, 'title': title, 'description': description, 'status': status, 'createdAt': createdAt, }; } }

JSON 解析这一块是新手最容易踩坑的地方。典型的报错是type 'Null' is not a subtype of type 'String',原因是后端返回的字段里有 null 值,而代码里用了强转as String。我的处理方式是给所有非必填字段设置默认值,用??运算符兜底,这样即使后端临时少了字段,也不会导致整个应用崩溃。

int 类型字段的转换也要小心。如果服务端把 id 序列化成字符串数字,json['id'] as int会直接抛异常。稳妥的做法是自己写类型转换工具,先判断类型再转,或者要求服务端统一格式。我在训练营实操中发现,很多同学习惯直接as int,结果后端一换就炸。这个毛病在商业项目里是致命伤,建议从一开始就写健壮的解析代码。

3.3 平台通道:Flutter 与 OpenHarmony 的通信桥梁

前面说到 Flutter 和 OpenHarmony 分属两个世界,如果需要调用系统原生的能力,就必须通过平台通道搭一座桥。在这个项目里,我用了 MethodChannel 来获取设备信息和系统版本,展示在清单页面底部:

Flutter 侧调用代码:

class DeviceInfo { static const MethodChannel _channel = MethodChannel('app/device_info'); static Future<String> getOsVersion() async { try { final String version = await _channel.invokeMethod('getOsVersion'); return version; } catch (e) { return 'unknown'; } } }

OpenHarmony 入口处理代码(ets 侧),核心是通过 context 获取系统属性:

import { Context } from '../application/Context'; export class EntryAbility { onCreate(context: Context) { let deviceInfo = context.getDeviceInfo(); let osVersion = deviceInfo.osFullName; // 保存 osVersion,等待 Flutter 通过通道获取 } }

实际操作中,通道名必须严格匹配,Flutter 侧 'app/device_info' 与原生侧注册名不一致的话,调用会直接报MissingPluginException。我建议通道名统一集中在一个常量文件里管理,避免手滑。

平台通道在这个项目里扮演的角色不大,但它是开发生态里理解跨平台原理的钥匙。训练营 DAY3 讲这个的目的,是为了让大家知道 Flutter 在 OpenHarmony 上并不是孤立的,它可以和系统原生能力打通。

4. UI 层实现与状态管理

4.1 数据清单页面的构建

清单页面是整个应用的主界面,结构上有加载中、加载成功、加载失败、空数据四种状态。UI 层我采用了简洁的列表布局,每行显示标题、描述和状态标签。

核心代码使用的是 Flutter 的 FutureBuilder。用一个 Future 触发 Dio 请求,在 builder 里根据 AsyncSnapshot 的状态切换页面显示。这套模式非常适合简单场景,不引入额外的状态管理库,代码量小且逻辑直白:

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('跨平台数据清单')), body: FutureBuilder<List<Item>>( future: _fetchData(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return ErrorView(message: snapshot.error.toString()); } final items = snapshot.data ?? []; if (items.isEmpty) { return EmptyView(); } return ListView.builder( itemCount: items.length, itemBuilder: (context, index) { final item = items[index]; return ListTile( title: Text(item.title), subtitle: Text(item.description), trailing: StatusTag(status: item.status), ); }, ); }, ), ); }

FutureBuilder 的设计我认为是 Flutter 对“简单场景下避免过度设计”的一个回应。状态管理库如 Provider、Riverpod 在大型项目里确实有用,但训练营的场景只是拉一次数据、渲染个列表,如果用上这些库反而把简单问题复杂化。读代码的难度直线上升。

一个实操细节:FutureBuilder 里的 future 如果放在 build 方法里直接创建,每次重建都会重新触发请求。更稳妥的做法是把 Future 缓存到 StatefulWidget 的 state 属性里,只在 initState 中创建一次。不然的话,用户只是点击了一下按钮触发 setState,整个列表就会重新去请求接口,加上 loading 闪烁,体验很差。

4.2 下拉刷新与分页加载机制

数据清单应用在实际使用中不可能只拉一页数据,分页加载是刚需。训练营里虽然只是简单调通接口,我在自己实操时额外加了刷新和分页逻辑,这里一并写出来。

下拉刷新用的是 RefreshIndicator,关键在于 onRefresh 回调要返回一个 Future,这个 Future 完成时刷新动画才会停止:

Future<void> _handleRefresh() async { _page = 1; final items = await _fetchList(_page); setState(() { _items = items; }); }

分页加载的核心是 ScrollController 监听滚动位置,当接近底部时自动加载下一页。这里我叠加了一个底部 loading widget,用_hasMore变量控制是否还有更多数据:

_scrollController.addListener(() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200) { _loadMore(); } });

分页场景最容易踩的坑是重复请求。用户快速滚动到底部,监听器被触发多次,每次都会发请求,造成数据重复。我的方案是在_isLoadingMore标记位,请求期间直接 return,避免并发。这类问题如果出现在生产环境,轻则浪费流量,重则导致界面数据错乱。

4.3 状态管理与页面间数据共享

当清单页面点击某条数据进入详情页时,需要把这条数据传递过去。在 Flutter 里最简单的方式是构造函数传参。但一旦页面层级变深,这种传参方式就会变得繁琐。训练营里我采用的是轻量方案:创建一个共享的全局状态类,用 ChangeNotifier 管理当前选中项。

class SharedState extends ChangeNotifier { Item? _selectedItem; Item? get selectedItem => _selectedItem; void setSelectedItem(Item item) { _selectedItem = item; notifyListeners(); } }

详情页监听这个状态的变化,自动刷新 UI。这个方案本质上就是最简单的 InheritedWidget 封装,不需要引入任何第三方库,却能解决两个页面之间共享数据的问题。这个训练营的阶段性目标不是打造一个大而全的企业应用,把所有项目都用上的思想是明确可取的:先动手跑通,再一步步加深理解。

当然,如果还要进一步扩展(比如增加登录、多模块交互、持久化),那确实需要引入 Riverpod 或者 Bloc 这类完整的方案。但这个判断要有依据,不能为了用而用。

5. 集成构建与运行调试

5.1 Flutter 构建产物与 OpenHarmony 工程整合

把 Flutter 工程和 OpenHarmony 工程整合起来,是整个训练营里最考验耐心的环节。第一步是用 Flutter 命令打出 OpenHarmony 平台需要的产物:

flutter build hap --release

这行命令会生成 HAP 格式的包,包含了 Flutter engine 的 so 文件和 Dart 编译后的产物。如果 flutter 环境配置正确,这个命令执行起来会很顺畅。如果报错提示找不到 OpenHarmony 平台,检查一下 Flutter SDK 是否为支持 OpenHarmony 的分支。

构建完成后,在 Flutter 工程目录下会生成 build/hap 文件夹,里面有编译好的 HAP 包。这个包可以直接安装到 OpenHarmony 设备上运行。但训练营工程里,采用的方式是把它导入到 DevEco Studio 工程里统一管理,这样能借助 IDE 的能力做签名和调测。

导入的具体操作是:把 HAP 包拷贝到 ohos_app 工程的 entry/libs 目录下,然后在 DevEco Studio 里配置依赖。配置完成后,工程树里会多出一个 Flutter 相关的依赖项,这样每次点击 Run,DevEco Studio 会自动把 Flutter 的 HAP 和 OpenHarmony 原生部分一起打包。我没有在这步遇到依赖冲突的问题,整合的流程整体已经比较成熟了。

5.2 模拟器与真机运行调试

在模拟器上跑项目比真机省事。训练营提供的是 OpenHarmony 模拟器,运行方式和 Android 模拟器类似,只是底层换成了 OpenHarmony 系统。模拟器的优势是可玩性强,方便截图和录屏,适合演示场景,但网络请求的测试必须注意:模拟器环境和宿主机网络共享,localhost 在本机有效,但如果请求的接口部署在远程服务器上,不需要做额外配置。

真机运行更像“实战”。连接设备后,DevEco Studio 会自动安装 HAP 包。真机上第一个要注意的是存储权限和网络权限,虽然 manifest 里已经声明了 INTERNET,但部分定制系统的安全策略还会多一层用户授权弹窗,运行时要盯着手机上是否有授权弹窗弹出。第二个注意点是开发调试模式下的日志输出,Flutter 侧的日志和 OpenHarmony 侧的日志是各自独立的,需要用各自的日志工具分别查看,不要混着找。

我在真机上调试时碰到的诡异问题是用 HAP 安装后,应用日志打印不出来。折腾了半天,后来发现是日志等级过滤问题。DevEco Studio 的日志控制台需要设置到 Debug 级别以下,才能看到 Flutter 打印的 debugPrint 输出。这个问题不涉及代码正确性,纯粹是调试工具的使用经验,记录下来给各位少走弯路。

5.3 HiLog 与 Flutter 日志联动排查

混合开发有一个很尴尬的地方:Dio 的异常可能在 Flutter 侧抛,也可能在系统网络栈里抛,光看一端的日志很难定位根因。我的做法是在 Flutter 侧给 Dio 加一个 LogInterceptor,把请求地址、耗时、响应码、返回体全部打印出来,然后再通过 Flutter 控制台统一查看:

dio.interceptors.add(LogInterceptor( requestBody: true, responseBody: true, requestHeader: true, ));

LogInterceptor 打出来的日志包含完整请求链路,对于快速定位问题非常有帮助。如果 Flutter 侧日志看不到网络请求记录,大概率是数据根本没走到 Dio,问题出在 UI 层或者路由层;如果能看到请求发出但收不到响应,则需要去 OpenHarmony 侧的 HiLog 里看系统网络栈的情况。

HiLog 是 OpenHarmony 的系统日志工具,查询方式是在 DevEco Studio 的 Log 窗口选择 HiLog 类型,按服务的 tag 过滤。我实际排查时发现在 Flutter 侧是能正常发请求的,但服务端始终没收到,最后通过 HiLog 看到是 DNS 解析失败。起初还以为是网络权限没配,后来排查发现是模拟器的网络桥接方式有问题,切换成 NAT 模式就好了。这些环境性的坑会在后面常见问题里集中总结。

6. 常见问题与排查技巧实录

6.1 请求到服务端但无响应的典型原因

这个现象的成因很多,这里按出现频率从高到低排队:

  • 网络权限未配置或配置错误。检查 module.json5 的 requestPermissions 是否包含 INTERNET。这步是我见过最多的情况。
  • 模拟器网络模式问题。部分模拟器默认网络模式是受限的,改到 NAT 模式后恢复。
  • baseUrl 配置错误。检查 Dio 的 BaseOptions.baseUrl 是否有做额外拼接,接口路径是否包含多余斜杠。
  • 证书问题。OpenHarmony 对部分 HTTPS 证书的信任策略不同,测试环境如果用的是自签证书,需要做额外的信任配置。
  • 防火墙屏蔽。开发机上如果开了防火墙,需要在出站规则里放行相关端口。

排查顺序建议先看 Flutter 控制台有没有 LogInterceptor 的输出,再看 HiLog 有没有系统层报错。如果 Flutter 侧已经打印出请求和返回状态码,那就直接看返回体内容;如果请求发出后杳无音信,优先怀疑网络环境和权限。

6.2 JSON 解析中的类型转换异常

这个项目里的列表数据里,后端可能返回 null 值或者类型不一致。最典型的是CreatedAt字段,服务端返回的是时间字符串,但偶尔会为 null。解析时如果直接as String就会崩。解决思路是给所有字段设置默认值,或者写一个isNotNull判断。

另一个容易出问题的字段是id。为了通用性,后端有时会把 id 设计成字符串类型,但如果客户端按 int 解析,在 Flutter 上编译能通过,运行时却会抛type 'String' is not a subtype of type 'int'。训练营里演示的做法是后端强行统一返回 int,但真实项目里不可控,所以我在自己的代码里写了一个自定义转换逻辑,先判断 runtimeType 再做转换,这样后端即使改类型也不会崩。

6.3 平台通道 ModuleNotFound 与 MissingPluginException

MissingPluginException 是 Flutter 混合开发里最常见的异常。它表示 Flutter 侧尝试调用一个原生插件,但原生侧并未注册。排查步骤按顺序是:检查通道名拼写是否一致,检查原生侧插件是否在工程里注册,检查构建产物是否已更新。有时候改完原生侧代码重新 Run 之后,Flutter 侧还没有热重启,这时需要在 flutter clean 后重建。

另外一种情况是 Flutter 引擎初始化失败导致的 MissingPluginException,典型的日志是 engine 初始化时报找不到 so 库。这种问题一般和环境变量有关,Flutter SDK 的 OpenHarmony 分支需要特定版本的预编译产物,重新 flutter upgrade 后在本地重新编译即可。

6.4 构建超时与依赖冲突处理

OpenHarmony 工程的构建偶尔会因为网络原因下载依赖失败,国内环境下这个现象尤其明显。DevEco Studio 的 build 日志里如果出现timeout、Could not resolve之类的字样,大概率是仓库连接超时。处理方式是检查仓库配置,确认使用的是可访问的源,然后清缓存重新构建。

依赖冲突则多发生在 Flutter 插件版本和 OpenHarmony 平台版本不匹配的情况。我在实操时遇到过 flutter_ohos 分支和某个插件版本要求不一致的问题,解决方式是锁定 Flutter SDK 分支版本,尽量保持插件靠后更新。

7. 训练营总结与后续扩展建议

整个 DAY3 训练营项目跑完,我的最大感受是:OpenHarmony 的跨平台开发生态已经不是纸上谈兵,而是真正到了可以落地的阶段。Flutter 负责交互和展示,Dio 负责网络数据,OpenHarmony 负责系统能力,这组分工配合默契,代码复用率高,开发效率也比预想的要好。

个人实操中最有价值的三点收获,一个是从零搭建一套完整流程的能力,包括环境准备、工程结构设计、权限配置、网络层封装、页面构建和最终打包;第二个是对平台通道的理解,它不仅仅是 Flutter 和 OpenHarmony 之间的桥,更是跨平台应用扩展原生能力的通用钥匙;第三个是排错经验积累,混合开发的坑往往不在某个具体框架里,而在于两端日志的衔接和联动,掌握这套排查思路,比记住几个 API 重要得多。

如果后续要把这个清单应用继续深入下去,可以考虑的方向有几个:首先是引入数据库做本地缓存,这样在无网络环境下也能看到历史数据;其次是增加登录鉴权体系,把 Dio 拦截器里的 token 刷新逻辑做完整;再者是接入现有状态管理框架,让整个应用能承载更复杂的业务模型;最后就是把 CI/CD 流程补上,用自动化脚本统一产出 HAP 包。

我在实际项目中用 Flutter 做 UI 层的频率越来越高,它的渲染精度的确能支撑复杂业务,而 OpenHarmony 作为底层系统,这两年的 API 完善度和稳定性进步都很明显。跨平台开发这条路已经越走越宽,剩下的更多是工程化实践的深度问题。希望这篇文章能给正在摸索 OpenHarmony + Flutter 组合的朋友一些底气和参考,少踩几个坑,多做几件实事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询