ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenHarmony上Flutter开发收支记录:从环境搭建到RK3568真机调试

OpenHarmony上Flutter开发收支记录:从环境搭建到RK3568真机调试 写这篇的时候我正坐在办公桌前对着 RK3568 开发板发呆。起因很简单社团要做一个内部管理的 App既要管成员信息又要记收支账目还要在 OpenHarmony 设备上跑起来。团队里有人提议用 ArkTS 从头写有人提议用 Flutter 快速出活后来我们选了第二条路然后一头扎进了Flutter for OpenHarmony这个还不太成熟但确实能跑通的生态里。这篇文章就把我做收支记录模块的过程完整复盘一遍包括选型理由、环境搭建、数据模型设计、UI 实现、持久化方案以及在真机上调试时踩到的一堆坑。如果你正准备在 OpenHarmony 上做 Flutter 应用尤其是带财务记账这种业务模块的这篇应该能帮你少走不少弯路。1. 为什么在 OpenHarmony 上选了 Flutter三条技术路线的实际对比先说结论OpenHarmony 上做应用开发目前主流路子有三条各有各的适用场景没有绝对好坏但结合社团管理 App 收支记录这个具体需求Flutter 的性价比是最高的。1.1 三条路线ArkTS 原生、Flutter 跨端、React Native 跨端第一条是纯 ArkTS 开发。这是 OpenHarmony 的亲儿子路线IDE 支持最完善文档最全API 调用最直接。但问题也很现实ArkTS 的生态成熟度跟 Flutter 比还是差了一截尤其是第三方 UI 组件库、图表库、日期选择器这些东西能找到的现成方案比较少很多时候得自己造轮子。社团管理 App 里有个收支统计图表如果用 ArkTS 画折线图和柱状图工作量不小。第二条是 React Native for OpenHarmony。RN 的优势是前端圈子大、热更新机制成熟但 OpenHarmony 上的 RN 适配进度一直不温不火很多原生模块没有对应实现遇到问题很难找到解决方案。我身边有朋友试过最后被各种桥接错误劝退了。第三条就是 Flutter for OpenHarmony。Flutter 的渲染引擎是自己实现的不依赖系统原生控件这意味着它的跨端一致性和可移植性天然比 RN 好。OpenHarmony SIG 社区有一个专门的 flutter_flutter 仓库在做适配目前已经能跑起大体量应用了。对我们这种需求明确的业务型 App 来说Flutter 的 UI 开发效率确实高一套代码将来还能复用到 Android 和 iOS社团里如果有人在用 iOS 手机后续做移动端版本也方便。1.2 收支记录模块对技术选型的三个关键要求我做选型的时候给收支记录模块列了三个硬性要求这三个要求直接决定了 Flutter 是最优解。第一是表单交互要流畅。收支记录的核心操作是录入数据涉及到金额键盘、分类选择、日期选择、备注输入这几个控件。Flutter 的 TextField、showDatePicker、BottomSheet 这些内置组件在 OpenHarmony 上适配得不错做出来的交互手感和原生 App 很接近不需要自己实现复杂的手势逻辑。第二是数据统计要直观。社团的收支记录不是记完就完事了期末要汇总、要按活动分类看开销、要对比收入支出占比。Flutter 生态里有 fl_chart 这样的图表库虽然 OpenHarmony 适配版可能需要自己处理一些细节但比从零写一个图表库省太多事了。第三是团队上手成本要低。社团的开发者都是学生水平参差不齐。Flutter 的 Dart 语言语法简单UI 是组合式写法新人培训成本比 ArkTS 和 RN 都低。我让两个之前只写过 Vue 的同学直接上手写页面一天就能出活了。提示如果你们的应用对系统深层次能力比如分布式软总线、蓝牙、USB 等依赖很重那别犹豫直接走 ArkTS 原生路线。Flutter for OpenHarmony 目前的定位还是偏普通应用场景系统级 API 的覆盖不如原生全面。我们的 App 只需要本地记账和数据库不涉及分布式能力所以 Flutter 完全够用。2. 搭环境这一步比你想的更费劲DevEco Studio、hdc 和 Flutter SDK 的三角关系OpenHarmony 的 Flutter 开发环境搭建跟 Android 不一样不是装个 Flutter SDK 就完事了。你需要同时搞定 OpenHarmony 的 IDE、命令行工具和 Flutter 的 OpenHarmony 分支这三者之间的版本匹配关系一旦搞错后面全是问题。2.1 工具链清单和版本匹配表我折腾了几轮之后最终稳定的版本组合是这样的工具版本备注DevEco Studio4.0 Release带 OpenHarmony SDKAPI 10OpenHarmony SDKAPI 10在 DevEco 里通过 SDK Manager 安装hdc随 DevEco 附带路径在 SDK 目录下的 toolchains 里Flutter SDKflutter_flutter 仓库的 ohos 分支基于 Flutter 3.7.x不要用官网原版 FlutterDart SDK随 Flutter SDK 附带版本 2.19.x这里最关键的认知是Flutter for OpenHarmony 不是一个独立的框架而是 Flutter 官方 SDK 的 fork。OpenHarmony SIG 在 GitHub 上维护了 flutter_flutter 和 flutter_engine 两个仓库你需要拉取这些仓库的特定分支而不是用 flutter.dev 官网下载的 SDK。2.2 拉取和配置 Flutter SDK 的完整命令# 拉取 flutter_flutter 仓库的 ohos 分支 git clone -b ohos https://gitee.com/openharmony-sig/flutter_flutter.git # 拉取 flutter_engine 仓库用于编译引擎如果只是开发可以不主动拉 git clone -b ohos https://gitee.com/openharmony-sig/flutter_engine.git # 把 flutter/bin 加入 PATH export PATH$PATH:$(pwd)/flutter_flutter/bin # 运行 flutter doctor检查 OpenHarmony 相关配置 flutter doctor --verboseflutter doctor 的输出会指导你安装一些 Android 工具链但注意OpenHarmony 开发并不需要完整的 Android SDKdevicectl 那部分可以忽略只要看到 flutter、Dart、DevEco Studio 这部分没问题就行。然后你需要在项目的 pubspec.yaml 里配置一个额外的依赖源因为部分 OpenHarmony 适配的包不在 pub.dev 上# pubspec.yaml environment: sdk: 2.19.0 4.0.0 dependencies: flutter: sdk: flutter provider: ^6.1.1 path_provider: ^2.0.15 hive: ^2.2.3 hive_flutter: ^1.1.0 # 如果想用 OpenHarmony 移植版的社区包可以加下面的源 # 但实际上核心包官方 pub.dev 已经有了不需要额外配源2.3 创建 Flutter 工程并适配 OpenHarmony 目录创建一个普通 Flutter 工程之后你需要用 DevEco Studio 打开工程然后它会自动识别出 Flutter 模块补充生成 OpenHarmony 的工程外壳。这一步我没法给出一套必定成功的 GUI 操作指南因为 DevEco Studio 每个小版本菜单有一点点差异但整体思路是在 DevEco Studio 里选择导入 Flutter 工程。指定到你的 flutter 项目根目录。DevEco 会提示你配置 SDK 和 hdc 路径。工程生成后你会看到一个ohos目录这就是 OpenHarmony 侧的壳工程。注意ohos目录是自动生成的不要手动往里面添加 Flutter 代码。你所有的 Dart 代码依然写在lib目录里然后通过 flutter build hap 命令构建出 OpenHarmony 的应用包HAP 文件。2.4 hdc 的坑先用hdc version验证连接hdc 相当于 Android 的 adb是连接开发板和模拟器的核心工具。配置 DevEco Studio 的时候它内部会自己找 hdc但如果你想在命令行里手动安装应用、看日志就得把 hdc 加到系统 PATH。我看热搜词里有hdc 查看 openharmony 系统版本 param get这个确实是常用命令。配好 hdc 之后用下面这条命令验证连接hdc version # 输出: HDC version 1.1.0 这种 # 查看连接的设备 hdc list targets # 查看 OpenHarmony 系统版本对应热搜里的 param get 用法 hdc shell param get const.ohos.fullname如果你连了设备但 hdc list targets 是空的先查两件事开发板有没有开启 USB 调试模式以及 DevEco Studio 里的 hdc 服务有没有占用端口。后一个坑我后面细讲。3. 收支记录的数据模型先想清楚记账这件事的逻辑再写代码很多新手写收支记录上来就建一个表id、金额、备注。然后写着写着发现要加分类、加支付方式、加活动关联表结构改来改去数据又要迁移。社团账目虽然简单但一样要按业务逻辑去设计模型。我在做这一块的时候反复推演了几次最终定下来这样一套结构。3.1 收支记录的核心字段设计一条收支记录LedgerRecord至少要包含这些信息字段类型说明idString使用 UUID不用自增 id方便将来多端同步typeint0 表示支出1 表示收入amountdouble金额单位是元保留两位小数categoryString分类编码如 activity、equipment、granttitleString摘要标题比如社团迎新晚会物料费noteString备注可空occurredAtDateTime实际发生时间createdAtDateTime记录创建时间operatorIdString经手人关联到成员表设计的时候有两个关键决策值得展开说一下。第一个决策是金额用 double 还是 int分。财务系统通常推荐用整数分避免浮点误差。但社团 App 金额通常不大而且 Dart 的 double 在加减运算时误差可控所以我用了 double。如果你担心精度可以在存储层转成 int 分存储展示层除以 100。我在项目里给了一个工具方法int toFen(double yuan) (yuan * 100).round(); double toYuan(int fen) fen / 100;第二个决策是分类是固定枚举还是动态维护。社团收支场景相对固定我预设了几个分类但允许用户在设置里自定义。分类用字符串编码而不是 int 索引这样新增分类不需要改数据库结构。class ExpenseCategory { final String code; final String name; final bool isIncome; const ExpenseCategory(this.code, this.name, {this.isIncome false}); } const ListExpenseCategory defaultCategories [ ExpenseCategory(activity, 活动经费), ExpenseCategory(equipment, 器材采购), ExpenseCategory(food, 餐饮团建), ExpenseCategory(transport, 交通出行), ExpenseCategory(other, 其他支出), ExpenseCategory(grant, 社团拨款, isIncome: true), ExpenseCategory(donation, 校友捐赠, isIncome: true), ];3.2 状态管理选型Provider 就是当前阶段的最优解OpenHarmony 上的 Flutter 状态管理我试过 Bloc 和 Riverpod最后选了 Provider。理由很朴素Provider 的依赖注入模型在 OpenHarmony 的适配层上最稳定学习曲线也平滑。Bloc 对事件的抽象做得很好但在 OpenHarmony 上偶尔会有 Stream 相关的兼容问题Riverpod 写起来很爽但 flutter_hooks 这类辅助包在 OpenHarmony 上的适配还不完整。Provider 的核心就三件事ChangeNotifier 负责管理状态ChangeNotifierProvider 负责提供状态Consumer/context.watch 负责消费状态并触发重建。下面是我定义的 LedgerControllerclass LedgerController extends ChangeNotifier { ListLedgerRecord _records []; bool _loading false; ListLedgerRecord get records List.unmodifiable(_records); bool get loading _loading; Futurevoid load() async { _loading true; notifyListeners(); _records await LedgerRepository.instance.getAll(); _loading false; notifyListeners(); } Futurevoid addRecord(LedgerRecord record) async { await LedgerRepository.instance.insert(record); _records.insert(0, record); notifyListeners(); } Futurevoid deleteRecord(String id) async { await LedgerRepository.instance.delete(id); _records.removeWhere((r) r.id id); notifyListeners(); } double get monthIncome { final now DateTime.now(); return _records .where((r) r.type 1 r.occurredAt.year now.year r.occurredAt.month now.month) .fold(0, (sum, r) sum r.amount); } double get monthExpense { final now DateTime.now(); return _records .where((r) r.type 0 r.occurredAt.year now.year r.occurredAt.month now.month) .fold(0, (sum, r) sum r.amount); } }这里有一个小技巧notifyListeners 不要在极端频繁的操作里反复调用。我在load()里是先设 loading 再一次性 notify后面重新赋值 records 后再通知一次这样 UI 不会因为多次 notify 造成不必要的重建。3.3 收支录入表单的交互细节录表单是收支记录最容易做烂的地方。最简单的做法是一排 TextField 加一个保存按钮但这样做出来的体验很糟糕。我在录入页做了几个针对性的处理。金额输入框用 TextInputType.numberWithOptions(decimal: true)并且在输入变化的时候做格式过滤只允许数字和一个小数点TextFormField( keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r^\d*\.?\d{0,2}))], decoration: const InputDecoration(labelText: 金额元), )类型切换用 SegmentedButtonFlutter 3.7 自带而不是两个 Tab。因为收入支出切换时下面的分类列表要跟着变化SegmentedButton 的 onSelectionChanged 回调可以同步更新分类区域。日期选择默认选中今天点击后弹出 showDatePicker。这里要注意 OpenHarmony 上 showDatePicker 的默认语言可能是英文需要在 MaterialApp 里配置本地化委托MaterialApp( localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [Locale(zh, CN)], locale: const Locale(zh, CN), home: LedgerPage(), )保存前校验金额必须大于 0标题不能为空。用 Form GlobalKey 做统一校验保存按钮的 onPressed 里先 validate 再提交。4. 收支列表与月度统计怎样把账目页面做得一眼看清收支记录的价值在于回顾所以列表页和统计摘要页是整个模块的视觉核心。我的目标是让用户打开 App 后不用任何操作一眼就能看到这个月收入多少、花了多少、结余多少、花在哪些地方最多。4.1 首页 Dashboard月度汇总卡片页面顶部放一个本月概览卡片用三个大数字显示收入、支出、结余。这个卡片我用了一个渐变背景的 Container 包着 ColumnContainer( padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF4A6CF7), Color(0xFF3B5BDB)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16), ), child: Row( children: [ _SummaryItem(label: 收入, value: controller.monthIncome), _SummaryItem(label: 支出, value: controller.monthExpense), _SummaryItem(label: 结余, value: controller.monthIncome - controller.monthExpense), ], ), )三个数字用等宽字体显示避免数字宽度变化引起视觉跳动。Dart 里可以用FontFeature.tabularFigures()来实现等宽数字效果OpenHarmony 的 Flutter 适配支持这个特性。4.2 分类占比基于 CircularProgressIndicator 自己画我原本想引入 fl_chart但在 OpenHarmony 上试了一下发现饼状图的交互点击展示详情有些兼容问题后来换了一种更稳妥的画法用 Flutter 自带的 CircularProgressIndicator 的 value 属性实现环形占比图再加一个图例列表。环形占比图本质是多个弧线拼在一起每个弧线代表一个分类的占比。Flutter 里可以用TweenAnimationBuilder做动画让它从 0 增长到目标值TweenAnimationBuilderdouble( tween: Tween(begin: 0, end: proportion), duration: const Duration(milliseconds: 600), builder: (context, value, _) { return CircularProgressIndicator( value: value, strokeWidth: 18, backgroundColor: Colors.grey.shade200, color: categoryColor, ); }, )但多个弧线拼接时需要控制value的起止范围每个分类的value是从start value到start value share。这个用 CircularProgressIndicator 做起来比较别扭我最后改成用CustomPaint画圆弧反而更干净。这里贴一个简化版class CategoryRingPainter extends CustomPainter { final ListCategoryShare shares; CategoryRingPainter(this.shares); override void paint(Canvas canvas, Size size) { final rect Offset.zero size; double startAngle -Math.pi / 2; for (final share in shares) { final sweepAngle share.proportion * 2 * Math.pi; final paint Paint() ..color share.color ..style PaintingStyle.stroke ..strokeWidth 18; canvas.drawArc(rect.deflate(9), startAngle, sweepAngle, false, paint); startAngle sweepAngle; } } override bool shouldRepaint(covariant CategoryRingPainter oldDelegate) true; }设计比例映射关系时注意圆弧的起始角是 3 点钟方向通常我们希望 12 点是起点所以把起始角偏移-Math.pi / 2。4.3 列表页按日期分组和左滑删除收支列表按时间倒序排列并按日期分组每组显示今天昨天或具体日期。这里有一个我在 Android 上没有遇到过但在 OpenHarmony 上容易出问题的地方中文日期和星期的格式化需要精确指定 locale。我在 3.3 里配置了 intl 包然后调用final formatter DateFormat(yyyy年M月d日 EEEE, zh_CN);至于左滑删除OpenHarmony 上的 Flutter 对 Dismissible 组件适配得还行可以直接用。但有一个坑如果列表项是一个 Stack 嵌套多个子组件Dismissible 的 background 在滑动时可能出现绘制闪烁。解决办法是用ClipRRect包住 Dismissible并确保每个列表项的 key 用的是记录 id。Dismissible( key: ValueKey(record.id), direction: DismissDirection.endToStart, background: Container( color: Colors.red, alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), child: const Icon(Icons.delete, color: Colors.white), ), onDismissed: (_) controller.deleteRecord(record.id), child: _RecordTile(record: record), )删除的时候要弹出确认框吗我的建议是不要弹但给一个 SnackBar 撤销按钮。社团场景下既要效率又要容错左滑删除直接执行同时显示已删除点此撤销这个交互比弹窗问你确定吗自然得多也更符合 Flutter 的 Material 设计规范。5. 持久化方案Hive 在 OpenHarmony 上的适配与坑收支记录是必须持久化的数据不可能一直在内存里。我在选持久化方案的时候对比了三种SharedPreferences、SQLitesqflite、Hive。5.1 为什么是 HiveSharedPreferences 适合存简单的键值对不适合存结构化列表。sqflite 是 Flutter 最常用的 SQLite 库但在 OpenHarmony 上需要 native 层支持官方适配还不完善主要问题在于编译时要找 SQLite 的动态库OpenHarmony 的 musl 库和 Android 的 bionic 库不太一样经常链接失败。Hive 是纯 Dart 实现的键值数据库没有原生依赖天然适合 OpenHarmony 这种新兴平台。Hive 的缺点是查询能力弱只能按 key 读取。但我们的场景是存一个列表 按时间倒序展示 按月汇总完全可以在内存里做数据量一学期几百条记录也足够小所以 Hive 很合适。5.2 Hive 的初始化和读写这里直接上代码。首先在 main 里初始化Futurevoid main() async { WidgetsFlutterBinding.ensureInitialized(); final dir await getApplicationDocumentsDirectory(); Hive.init(dir.path); Hive.registerAdapter(LedgerRecordAdapter()); await Hive.openBoxLedgerRecord(ledger); runApp(const MyApp()); }注意getApplicationDocumentsDirectory 是 path_provider 包提供的。path_provider 在 OpenHarmony 上有一个适配版本需要确保 pubspec 里用的是支持 OpenHarmony 的版本。实测下来 path_provider 2.0.x 在 OpenHarmony API 9 上可以正常工作。定义 Hive 的 TypeAdapter序列化和反序列化自定义对象class LedgerRecordAdapter extends TypeAdapterLedgerRecord { override final int typeId 0; override LedgerRecord read(BinaryReader reader) { return LedgerRecord( id: reader.readString(), type: reader.readInt(), amount: reader.readDouble(), category: reader.readString(), title: reader.readString(), note: reader.readString(), occurredAt: DateTime.fromMillisecondsSinceEpoch(reader.readInt()), createdAt: DateTime.fromMillisecondsSinceEpoch(reader.readInt()), operatorId: reader.readString(), ); } override void write(BinaryWriter writer, LedgerRecord obj) { writer.writeString(obj.id); writer.writeInt(obj.type); writer.writeDouble(obj.amount); writer.writeString(obj.category); writer.writeString(obj.title); writer.writeString(obj.note); writer.writeInt(obj.occurredAt.millisecondsSinceEpoch); writer.writeInt(obj.createdAt.millisecondsSinceEpoch); writer.writeString(obj.operatorId); } }TypeAdapter 的序列化顺序必须和 write/read 严格一致否则会读出脏数据。这是一个非常容易踩的坑尤其是你中途往模型里加了字段如果没有更新 Adapter旧数据读出来会对不上。5.3 模拟异常关闭导致的数据破损Hive 本身有 recovery 机制但如果 App 在写入过程中被强杀或者开发板突然断电开发板经常这样Hive 文件可能损坏。我在测试的时候遇到过两次打开 Box 直接抛异常的情况。解决办法是在初始化 Hive 时做一层 try-catch 保护Futurevoid safeInitHive() async { final dir await getApplicationDocumentsDirectory(); Hive.init(dir.path); try { await Hive.openBoxLedgerRecord(ledger); } catch (e) { // 如果文件损坏先删掉再重建避免启动崩溃 await Hive.deleteBoxFromDisk(ledger); await Hive.openBoxLedgerRecord(ledger); } }这在开发调试阶段很有用正式上线时还要考虑导出备份逻辑但至少不会因为一次异常关机就让整个 App 打不开。6. 真机联调与打包RK3568 开发板上的实测记录写完代码只是第一步真机跑起来才是真正的考验。我这里用的是 RK3568 开发板OpenHarmony 3.2 Release 系统。下面这条链路是我踩过无数坑之后总结出来的最短路径。6.1 hdc 连接与常见故障排查先讲连接。开发板通电USB 线连到电脑USB 调试模式打开。命令行执行# 先杀掉可能残留的 hdc server hdc kill # 启动 hdc server hdc start # 查看设备 hdc list targets如果 hdc list targets 能看到设备序列号说明连接成功。如果什么都看不到按照这个顺序排查检查开发板设置里的开发者选项确认 USB 调试已开启。OpenHarmony 有些镜像默认关闭需要在设置里手动打开。换一根支持数据传输的 USB 线。很多 Type-C 线只能充电不能传数据这个坑仅次于 Wi-Fi 信号差。检查 hdc 服务端口占用。DevEco Studio 自己会启动一个 hdc server占用端口 8710。如果你之前在命令行里启动过 hdc可能会冲突。最简单的办法是hdc kill然后再hdc start或者把 DevEco Studio 先关掉。看系统日志hdc hilog可以输出设备日志连接上了但没日志那多半是设备系统本身有问题。6.2 构建 HAP 包并安装到开发板在项目根目录执行flutter build hap --debug这会调用 OpenHarmony 的构建链生成 HAP 包。输出位置一般在build/ohos/phone/outputs/hap/project_name_phone_debug.hap然后通过 hdc 安装# 安装应用 hdc install ./build/ohos/phone/outputs/hap/my_app_phone_debug.hap如果安装时报 INSTALL_PARSE_FAILED 之类错误先确认 HAP 是不是用了与设备匹配的 OpenHarmony SDK 版本。API 10 的 HAP 装到 API 9 的板子上大概率会失败。运行应用hdc shell aa start -a MainAbility -b com.example.myappcom.example.myapp是你的 OpenHarmony 应用的 bundleName在 ohos 目录下的 module.json5 或 build-profile.json5 里配置。6.3 日志查看Flutter 日志和 OpenHarmony 日志怎么分开看开发中最常用的命令是# 查看所有 hilog hdc hilog # 过滤 Flutter 的日志Flutter 会打到 stdout hdc shell hilog | grep -i flutter不过 hdc hilog 的输出量非常大建议在 Flutter 代码里加 debugPrint然后通过hdc hilog | grep flutter过滤。如果你在 IDE 里调试DevEco Studio 的 Log 面板也可以直接看到 Flutter 的 print 输出但有时候会卡不如命令行来得直接。6.4 性能表现掉帧和耗电RK3568 的性能比主流手机弱不少Flutter 应用在上面跑会有明显的掉帧。我的实践经验是不要在列表里用图片加载框架比如 cached_network_image网络图片用原生Image.network就够了OpenHarmony 上 Flutter 的 HttpClient 走的是 Wi-Fi 栈缓存机制比较少。避免过度使用阴影和模糊效果。BoxShadow、BackdropFilter 这类视觉效果在 RK3568 上会严重拖慢帧率。我在月度卡片上用的渐变背景没问题但一开始给列表项加了 BoxShadow滑动明显不流畅去掉之后好了很多。热重载有概率失败在 OpenHarmony 上hot reload没有 Android 那么可靠改动多了直接r不行就R全量刷新再不行就重新 build。7. 踩坑实录OpenHarmony 上 Flutter 开发最容易翻车的四个地方最后集中说一下我在整个开发周期里印象最深的几个坑每一个都至少浪费了我半天时间。7.1 mybatis-plus 问题没遇到但 apply flutters main gradle plugin imperatively 这个问题遇到了热搜词里有一条you are applying flutters main gradle plugin imperatively using the apply s...这是 Android 工程里的 Gradle 报错OpenHarmony 也类似。它的含义是你用apply plugin:的方式应用了 Flutter 插件但新版 Gradle 要求用plugins {}声明式语法。OpenHarmony 的 flutter 构建流程偶尔会产生这种兼容问题解决办法是找到 ohos 目录下的 build.gradle 或 settings.gradle把apply plugin: dev.flutter.flutter-plugin-loader改成 plugins DSL 写法或者升级 Flutter SDK 到修复了此问题的版本。7.2 第三方包的 OpenHarmony 支持清单这是最疼的。大多数 pub.dev 上的 Flutter 包都依赖原生代码Android 的 Kotlin/Java、iOS 的 Objective-C/Swift在 OpenHarmony 上无法直接运行。我列一个我实测过的包支持情况供参考包名OpenHarmony 支持情况说明provider可用纯 Dart 实现无原生依赖hive / hive_flutter可用纯 Dart 实现path_provider可用有适配分支需要引入社区 fork 或等待官方适配intl可用纯 Dartfl_chart部分可用能画基本图表个别动画效果适配不佳dio可用纯 Dart 网络库cached_network_image不推荐图片缓存会失效性能差flutter_local_notifications不可用依赖系统通知服务OpenHarmony 未适配shared_preferences可用OpenHarmony 有官方适配版本sqflite不推荐原生库链接问题多建议换 Hive对于不支持的包短期内除了等社区适配只能自己动手改。如果你只是做业务型 App尽量把依赖控制在纯 Dart 生态里可以省去大量移植调核的时间。7.3 中文字体消失问题OpenHarmony 系统默认是没有 Flutter 自带的那套 Roboto 字体的中文渲染依赖系统的 HarmonyOS Sans。如果你在 Flutter 里指定了 fontFamily可能某些中文字符显示为方框。解决办法要么不指定 fontFamily让 Flutter 走系统字体栈要么在 assets 里打包一个中文字体文件例如 OppoSans 或 HarmonyOS Sans 的 TTF然后ThemeData( fontFamily: HarmonyOS_Sans, // 记得在 pubspec.yaml 里声明 assets/fonts/ 目录 )这个坑只会在 OpenHarmony 上出现在 Android/iOS 上不会因为那边的系统中文字体栈是完整的。7.4 devicectl 相关报错和真机部署的相似坑Flutter 的 device 发现机制在 OpenHarmony 上不是自动的。flutter devices可能看不到已经连接好的 RK3568这时候不要慌直接用 hdc install 手动部署不要依赖flutter run的自动安装功能。我在使用中flutter run -d device_id偶尔能识别但稳定性不如手动 hdc。所以我的工作流是flutter build hap --debug生成包hdc install安装hdc shell aa start启动。虽然多点几步但每一步都可控出问题也好定位。8. 后续还能怎么扩展图表升级和多端同步最后说一点我还在规划中的扩展方向如果你也是在社团或者校内团队做这类 App可以参考。当前版本的中文图是基于 CustomPaint 画的环形占比图够用但不够丰富。后面我打算把 fl_chart 或 community_chart 的 OpenHarmony 适配搞定加上折线趋势图展示月度收支变化曲线。这个需求很常见很多社团都有看这个学期经费是稳定增长还是突然超支的诉求。另外是同步问题。目前数据只存在本地 Hive 里如果换手机或者开发板坏了数据就丢了。后续打算用 OpenHarmony 的分布式数据管理服务来实现多端同步这样可以在开发板和手机之间共享账目。这个功能目前 Flutter 侧没有现成插件需要写 OpenHarmony 的原生插件做桥接工作量不小但意义也很大。如果你只是做一个小工具把 Hive 数据通过云服务手动备份也是更轻量的替代方案。做这个收支记录模块前后花了大概两周真正写业务代码的时间其实很少大部分时间都耗在环境适配和踩坑上。不过这也是前期做 OpenHarmony 应用必须经历的过程毕竟生态还没有像 Android 那么成熟。但反过来想正因为不成熟才有大量可以自建方案、积累经验的空间。等走过这一段你对 Flutter 渲染原理、OpenHarmony 系统结构理解都会上一个台阶。
返回列表