ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Flutter for OpenHarmony实战:分类管理功能开发全流程解析

Flutter for OpenHarmony实战:分类管理功能开发全流程解析 开源生态里做跨端开发最头疼的往往不是业务逻辑本身而是平台适配那一层看不见的坑。Flutter for OpenHarmony这组合我断断续续折腾了小半年从工程跑不起来到最终在真机上稳定运行中间踩过的坑比写业务代码的时间还多。这篇就拿一个生活助手App里最不起眼、但信息量很足的“分类管理功能”来说事把Flutter在OpenHarmony上的工程搭建、数据持久化、UI交互、组件通信到真机调试的完整链路过一遍。内容适合两类人一是刚把Flutter环境跑起来、想在OpenHarmony设备上做点实际功能的移动端开发者二是已经在鸿蒙生态里用ArkTS写过应用、想看看Flutter跨端方案在这套系统上能走多远的同学。代码和思路都从实际项目里来能直接照着改。1. 分类管理功能背后的设计思路与技术选型1.1 一个“简单”功能里藏着的三个技术难点分类管理在生活助手App里通常长这样首页一个分类列表每项有图标、名称、类型点击进入对应明细右上角能新增、编辑、排序、删除。表面看是标准CRUD但落到Flutter for OpenHarmony这个特定组合里就有三个不省心的点。第一个是数据持久化。OpenHarmony自带的关系型数据库接口是ohos.data.relationalStoreArkTS工程里用起来没问题但Flutter侧没法直接调这套API得走通道或者用第三方库封装。如果直接用Flutter生态里的sqflite默认依赖的是Android的SQLite实现在OpenHarmony上根本编不过。这就逼着你去翻社区的ohos分支或者干脆自己用MethodChannel把关系型数据库的能力桥接出来。第二个是图标和资源的加载路径。OpenHarmony上Flutter应用的资源打包路径、图标字体加载方式与Android有细微差异。分类功能免不了要选图标、配颜色处理不好就是运行时图标全变方块或者资源读取报错。这属于不跑真机绝对发现不了的一类问题。第三个是列表拖拽排序和频繁增删改时Flutter的列表组件与平台手势之间的冲突。OpenHarmony的触摸事件参数和Android有细微差别ReorderableListView这类组件需要做小幅度适配否则长按拖拽的触发阈值和震动反馈都怪怪的。把这三点拆开看分类管理就不再是“写个ListView加几个弹窗”的小事了它正好覆盖了数据层、资源层、交互层三个方向的适配问题非常适合作为验证Flutter在OpenHarmony上可用性的试金石。1.2 为什么选择Flutter而不是ArkTS或uni-app选Flutter for OpenHarmony做这个功能不是因为它比ArkTS更“高级”而是因为项目里有一大套已经写好的Flutter业务代码包括图表组件、登录模块、网络层全部重写成ArkTS的成本太高。Flutter的ohos适配分支社区通常叫flutter_flutter的ohos分支或者OpenHarmony sig-maintained版本存在的意义就是让这套代码尽量少改移植过去。另一个原因是团队里很多人已经熟悉Dart和Flutter的组件模型学习曲线比ArkTS平缓。ArkTS的声明式UI和状态管理本身也很成熟但如果团队本身没有鸿蒙原生开发经验强行切过去反而容易在状态管理和生命周期上翻车。Flutter的BuildContext、setState、InheritedWidget这套东西大家用得顺手。当然也必须承认Flutter在OpenHarmony上目前还不是官方一等公民部分系统能力比如直接调用分布式软总线、超级终端协同需要通过PlatformChannel桥接做不到像ArkTS那样天然融合。所以选型结论很明确如果你是从零开发一个只跑在鸿蒙设备上的应用ArkTS是更稳的路如果你有存量Flutter代码或者未来还想覆盖iOS、Android等多端Flutter for OpenHarmony就是性价比最高的选择。1.3 分类管理模块的整体架构设计我这边最终采用的分层结构是这样的UI层分类列表页、添加/编辑弹窗、图标选择器、排序设置页全部由Flutter Widget构建。状态层使用Riverpod管理分类列表数据配合ChangeNotifier监听数据变化。数据层封装CategoryRepository统一提供增删改查接口内部屏蔽具体存储实现。存储层默认走sqflite的OpenHarmony适配分支同时用shared_preferences缓存少量配置项。这么做最大的好处是如果某天OpenHarmony的数据库适配分支出问题只需要替换存储层实现Repository接口不变UI完全感知不到。final categoryRepository CategoryRepository(); // UI调用示例 final list await categoryRepository.getAllCategories();数据流方向也很简单页面加载时从Repository拉数据写入Riverpod的State用户操作触发方法调用先更新数据库成功后更新内存StateUI自动刷新。严禁直接改State绕过数据库否则会出现重启App后数据丢失这种“灵异事件”。2. 工程搭建与运行环境准备2.1 工具链清单与版本选择先在前面说个结论Flutter for OpenHarmony的环境搭建网上教程不少但版本匹配极其敏感照着老教程配新版工具链大概率跑不起来。我这里用的组合是OpenHarmony SDKAPI 104.0 Release对应DevEco Studio 4.0。Flutter SDKOpenHarmony社区维护的ohos分支版本对应Flutter 3.7左右。开发IDEDevEco Studio负责OpenHarmony工程编译和真机调试VS Code负责写Dart代码。真机Dayu 200开发板或RK3568系列系统版本和SDK一致。有个容易忽略的点OpenHarmony SDK需要你手动安装ohos-sdk并配置HarmonyOS相关环境变量。很多人在这一步直接用DevEco Studio默认路径结果命令行里flutter doctor永远检测不到OpenHarmony平台项目创建后压根没有ohos目录。命令行工具方面需要把sdk\default\openharmony\toolchains加到PATH里同时确认node和hvigw可用。hvigor是OpenHarmony的构建工具相当于Android里的Gradle后面很多编译问题都跟它有关。2.2 创建并配置ohos工程的几个关键步骤用社区分支的Flutter SDK创建项目时不能直接执行flutter create完事还需要手动添加OpenHarmony平台目录。我的做法是用flutter create生成标准Flutter工程语言选Dart平台只勾android和ios先不碰ohos。把OpenHarmony工程模板拷贝到工程根目录重命名为ohos并修改里面的build-profile.json5把signingConfigs指向你自己的签名文件。在pubspec.yaml里引入适配过的插件分支比如sqflite用git方式指向ohos适配仓库。修改ohos/entry/src/main/module.json5确认deviceTypes包含phone或tablet否则装不上真机。签名这一步容易被跳过但实际上非常关键。OpenHarmony不像Android可以随便装debug包真机安装必须有过签名的hap包。没有配置签名文件的话后面hvigor虽然能出包但装上设备后会提示安装失败或者验证失败。注意OpenHarmony的调试签名需要在DevEco Studio里生成生成后把.cer、.p12、.p7b三个文件路径填到build-profile.json5对应的signingConfigs里即可。别用自动生成的临时签名去跑长时间测试会有过期时间。2.3 首次运行必须检查的三件事工程配置完第一件事不是写代码而是跑通一个空应用的真机安装流程。我建议你依次检查三个东西能省掉后面大量排查时间。第一检查flutter devices能否识别到OpenHarmony设备。正常情况会列出类似OHOS device的项如果看不到多半是hdc鸿蒙设备连接工具没有启动或者设备没开启开发者模式。在DevEco Studio里能连上设备的话命令行里一般也没问题。第二检查flutter run -d ohos能不能热重载。OpenHarmony分支的热重载能力比Android上弱一些但基本可用。如果一运行就崩先看是不是签名问题——报Install Failed: error: signature verification failed这类错误时九成是签名没配对。第三检查控制台输出的日志等级。OpenHarmony的hilog和Android的logcat格式不同Flutter的print输出在hilog里默认可能被过滤掉。我习惯在跑之前加上--verbose参数或者直接用DevEco Studio的Log窗口过滤Dart关键字否则很多运行时错误根本看不到。这三件事都通过后才算真正具备开发条件。很多时候所谓的“Flutter新建项目后跑不起来”其实都死在这三个环境细节上跟业务代码一点关系都没有。3. 分类管理的数据层设计3.1 分类数据模型该怎么定义分类业务上一般有两种支出分类和收入分类。生活助手App里购物、餐饮、交通是支出工资、理财收益是收入。我在模型里加了一个type字段区分后续统计报表会按这个字段分组。Dart模型定义如下class Category { final int? id; final String name; final String icon; final int iconColor; final int type; // 0支出, 1收入 final int sortOrder; final bool isDefault; Category({ this.id, required this.name, required this.icon, required this.iconColor, required this.type, required this.sortOrder, this.isDefault false, }); MapString, dynamic toMap() { return { id: id, name: name, icon: icon, icon_color: iconColor, type: type, sort_order: sortOrder, is_default: isDefault ? 1 : 0, }; } factory Category.fromMap(MapString, dynamic map) { return Category( id: map[id], name: map[name], icon: map[icon], iconColor: map[icon_color], type: map[type], sortOrder: map[sort_order], isDefault: map[is_default] 1, ); } }icon字段我存的是图标字体的Unicode码点字符串比如0xe600而不是直接存图片路径。这样换主题、换图标库时不用改数据库UI层按码点渲染即可。iconColor存的是ARGB整数值Flutter的Color可以直接用但要注意OpenHarmony上字体渲染对透明通道的处理跟Android不完全一样部分设备上Color(0x00000000)会渲染成纯白建议颜色值全部带不透明alpha。3.2 存储方案选型为什么盯上sqflite适配分支数据存储这边我首推的还是SQLite。OpenHarmony自身有关系型数据库但Flutter侧要跨语言调用信息密度和事务控制都会受限。SQLite在Flutter生态里足够成熟SQL语法统一后期如果要同步到服务端迁移成本也低。但直接写import package:sqflite/sqflite.dart在OpenHarmony上是编译不过的因为原版sqflite底层依赖Android的SQLite实现。OpenHarmony社区里有人维护了适配版通过ffi直接调OpenHarmony的native SQLite接口。用的时候需要在pubspec.yaml里写成dependencies: sqflite: git: url: https://gitee.com/xxx/sqflite_ohos.git ref: ohos_main加载的插件名也会变化初始化时记得用openDatabase的factory参数指定final db await openDatabase( path, version: 1, onCreate: (db, version) async { await db.execute( CREATE TABLE categories( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, icon TEXT, icon_color INTEGER, type INTEGER, sort_order INTEGER, is_default INTEGER ) ); }, );其实还有一个更轻量的思路分类数据量通常很小几十条撑死用shared_preferences存JSON也不是不行。但如果App未来还要加流水记录、账单分析分类表迟早要跟其他表做关联查询所以一步到位上SQLite是更稳的选择。提示如果实在不愿引第三方适配库也可以自己用MethodChannel桥接OpenHarmony的relationalStore。工作量大概多一两天但要处理异步回调、数据类型转换、事务边界我这边实测下来还是直接用适配分支省心。3.3 默认分类初始化与Repository封装首次启动时分类表是空的需要在用户看到页面之前插入一组默认分类。这个逻辑不建议直接写在页面初始化里而是收敛到CategoryRepository的initDefaultData()方法。class CategoryRepository { static const _defaultCategories [ {name: 餐饮, icon: 0xe601, color: 0xFF4CAF50, type: 0}, {name: 购物, icon: 0xe602, color: 0xFFFF9800, type: 0}, {name: 交通, icon: 0xe603, color: 0xFF2196F3, type: 0}, {name: 工资, icon: 0xe604, color: 0xFF009688, type: 1}, ]; Futurevoid initDefaultData(Database db) async { final count Sqflite.firstIntValue( await db.rawQuery(SELECT COUNT(*) FROM categories), ); if (count 0) { final batch db.batch(); for (final c in _defaultCategories) { batch.insert(categories, { name: c[name], icon: c[icon], icon_color: c[color], type: c[type], sort_order: 0, is_default: 1, }); } await batch.commit(noResult: true); } } }为什么用count 0作为判断条件而不是单独存一个“是否初始化”的标记因为如果用户删光了所有默认分类再重启App标记法会重新插一遍默认数据用户会以为App出bug了用count判断则尊重用户的操作结果。这个小细节我是在用户反馈“删光分类后重启又冒出来”之后才改掉的。Repository对外只暴露getAllCategories、insertCategory、updateCategory、deleteCategory、reorderCategories这五个方法内部全部用Future异步。所有数据库路径都通过getDatabasesPath()拼接不要写死绝对路径OpenHarmony的沙箱路径跟Android不一样写死了一定挂。4. UI交互实现列表、弹窗与图标选择4.1 分类列表主页面布局与手势冲突处理主页面结构不复杂顶部标题栏下面一个ReorderableListView每个列表项显示图标、名称、类型标签右侧一个拖拽手柄。但OpenHarmony上这个列表的拖拽体验和Android有差异主要表现为长按触发拖拽时列表滚动与拖拽的判定经常打架很容易把“滚动”误判成“拖拽”。解决方案是使用ReorderableListView.builder并把buildDefaultDragHandles设为false自己包一个拖拽图标作为ReorderableDelayedDragStartListener的子组件ReorderableListView.builder( buildDefaultDragHandles: false, itemCount: categories.length, onReorder: (oldIndex, newIndex) { setState(() { if (newIndex oldIndex) newIndex - 1; final item categories.removeAt(oldIndex); categories.insert(newIndex, item); }); _repository.reorderCategories(categories); }, itemBuilder: (context, index) { final item categories[index]; return ReorderableDelayedDragStartListener( key: ValueKey(item.id), index: index, enabled: !item.isDefault, // 默认分类不可拖拽 child: _buildCategoryItem(item), ); }, )注意onReorder里那个newIndex oldIndex时要减一的逻辑。这是ReorderableListView老生常谈的坑向下拖动时newIndex传入的是移除前的位置必须修正否则顺序永远错一位。我在OpenHarmony上实测这个坑依然存在没被适配分支修掉。默认分类不可拖拽这一点我通过enabled: !item.isDefault来控制。用户反馈里经常有人误操作把“餐饮”拖到最底部然后统计报表排序乱了又来投诉干脆直接禁掉最稳。4.2 添加与编辑分类弹窗的实现细节添加和编辑可以用同一个弹窗组件通过传入的Category?参数区分。弹窗里核心就三块名称输入框、类型切换、图标选择入口。名称输入框有一个容易踩的坑OpenHarmony的输入法弹起时弹窗组件可能会被顶出屏幕。Flutter的showDialog在Android上默认会resizeToAvoidBottomInset但在OpenHarmony适配分支上这个特性并不可靠。我的解决办法是给弹窗内容包一层SingleChildScrollView并监听MediaQuery.of(context).viewInsets.bottom动态调整底部paddingPadding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, ), child: SingleChildScrollView( child: _buildForm(), ), )类型切换用SegmentedButton就行Android上这个组件表现良好OpenHarmony上只要色彩主题不是太偏门也没问题。不过要注意SegmentedButton是Material 3组件如果项目里用的是Material 2主题要先升级主题否则运行时会直接抛异常。保存逻辑统一走_repository.insertCategory或updateCategory成功后Navigator.pop并在弹窗打开的页面里通过await showDialog(...)拿到返回值后刷新列表。不建议在Repository里直接发通知更新状态因为弹窗可能同时存在多个实例返回值的方式更直观可控。4.3 图标选择器与颜色配置的交互方案分类图标这里我踩过大坑。一开始图省事用Flutter内置的Icons字体结果OpenHarmony上部分图标字形渲染异常显示成方块。后来改成自托管图标字体从阿里iconfont里挑一批分类图标生成ttf放进assets/fonts在pubspec.yaml里声明后用IconData自定义码点渲染。字体声明flutter: fonts: - family: CategoryIcons fonts: - asset: assets/fonts/category_icons.ttf运行时Icon(IconData(codePoint, fontFamily: CategoryIcons))其中codePoint就是从数据库读出来的0xe601之类的值。这样图标、颜色都数据化了用户自定义分类时甚至可以自己选颜色。图标选择器我用的是一个横向滚动的GridView弹层按类型分组展示。交互上有个细节选完图标后立刻反馈到列表预览不要等用户点“确定”才生效。因为分类功能的变更频率高反馈快一点用户会觉得应用响应迅速。颜色选择做成了预设色板8个纯色加上透明度选项。注意颜色存数据库时用int即可但OpenHarmony某些设备在渲染低饱和色时有色偏我实测下来0xFF开头的纯色最稳太花哨的渐变效果在低端开发板上会掉帧。5. 状态管理与组件通信从setState到Riverpod5.1 为什么分类列表不能只用setState硬扛早期的分类页面只有几十条数据我用setState维护列表修改列表项直接改内存数组看起来没什么问题。但后来加了统计页面之后分类列表的变更需要同时刷新首页的收支汇总、账单页的下拉筛选再靠setState一层层往上回调代码就变成了一坨。Flutter官方的做法是状态提升但提升到根Widget之后所有子组件都跟着重建性能损耗虽然分类场景下感觉不到但代码可维护性很差。是时候引入统一的状态管理方案了。我在这个工程里用的是Riverpod理由是它对异步操作的支持比Provider更自然FutureProvider可以优雅地处理“从数据库读数据”这种场景不需要手动管理loading状态。当然如果你更熟悉Provider或者Bloc也完全可以核心思路是一致的把分类列表抽成全局单例状态任何组件都能监听任何组件都能通过Provider内的方法修改。5.2 Flutter组件通信的几种姿势对比在分类管理这个模块里我实际用到的组件通信方式有三种按场景区分第一种是父传子直接构造参数传递。比如列表项CategoryItem需要接收Category对象和拖拽回调直接在构造函数里传简单直白。这种方式的缺点是深层次传递时需要一层层透传但项目里只有两层问题不大。第二种是子传父用回调函数。弹窗保存成功之后通过Navigator.pop(result)把结果抛回给列表页列表页根据返回值执行刷新操作。这个模式适合一对一、一次性的通信代码流程清晰不容易出bug。第三种是跨组件状态同步用Riverpod的StateNotifierProvider。分类页和统计页都要监听同一份分类数据这时候用回调就会乱套——统计页怎么拿到分类页的更新通知用全局Provider就干净了final categoryListProvider StateNotifierProviderCategoryListNotifier, ListCategory((ref) { return CategoryListNotifier(); }); class CategoryListNotifier extends StateNotifierListCategory { CategoryListNotifier() : super([]); Futurevoid load() async { final repo CategoryRepository(); state await repo.getAllCategories(); } Futurevoid add(Category category) async { final repo CategoryRepository(); final id await repo.insertCategory(category); state [...state, category.copyWith(id: id)]; } Futurevoid remove(int id) async { await repo.deleteCategory(id); state state.where((c) c.id ! id).toList(); } }关键点所有数据库操作成功后才更新state。先改state再写库一旦数据库写入失败界面和数据就分叉了。我见过不少新手在这里翻车。5.3 数据更新后UI自动同步的坑Riverpod用起来之后大部分UI同步问题都消失了但有个隐藏坑值得单独说列表项的key问题。ReorderableListView要求每个item必须有唯一的key我用的是ValueKey(item.id)。但如果新增分类后数据库返回的id是自增的可能和之前删除的某个分类id重复虽然SQLite自增不会立即复用但某些情况下会。一旦key重复列表会出现诡异的复用错乱——图标对不上名字拖拽后条目乱跳。解决方法是插入后立刻用数据库返回的id构建新对象并且给列表项加一个不可变的uniqueKey字段用uuid生成彻底避免依赖自增id。这个小改动花了我半小时但排除了一个极难复现的线上bug。组件通信这件事原则就是能用参数传递就别引入全局状态能用局部回调就别把事件总线引进来。项目规模没到一定复杂度时过度设计比不用设计更坑。6. 真机调试与常见问题排查实录6.1 “跑不起来”的三大元凶Flutter for OpenHarmony最常见的问题永远是“新建项目后跑不起来”。我帮别人排查过好几次九成都是下面三个原因之一。第一是SDK路径没配对。DevEco Studio装的鸿蒙SDK路径和命令行里flutter doctor检测到的路径不一致或者PATH里没有sdk/default/openharmony/toolchains导致hdc找不到。检查方法很简单命令行执行hdc list targets有设备输出就说明连接工具没问题。第二是签名配置缺失或过期。OpenHarmony真机安装应用必须有签名调试签名有效期通常只有三个月。如果hvigor构建时没报错但安装到设备提示Install Failed: info: error: verify signature failed那就是签名过期了去DevEco Studio重新生成即可。第三是工程模板版本不匹配。OpenHarmony API版本和Flutter ohos分支版本是绑定的API 9的工程配API 11的SDK或者反过来都会在编译阶段报错。选型时先锁定一组我在2.1节给出的那组组合实测最稳你自己搭环境时优先找对应版本的配套文档别混搭。6.2 Dart运行时与资源加载报错的处理运行阶段报错里出现频率最高的是类似这种E/flutter (31173): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled exception后面通常会跟着一个Dart堆栈。大部分时候这是业务代码抛的异常被Flutter全局捕获了但OpenHarmony上有一个特殊原因dart_vm_initializer.cc报错往往伴随着isolate初始化失败尤其是用了多个isolate做后台计算时OpenHarmony适配分支的isolate支持还不太完善。我的建议是分类管理这种轻量操作尽量别开新isolate直接用async/await就够了。如果必须走isolate测试时重点验证真机场景模拟器上不稳定的问题真机上可能更严重。另一个资源加载类报错是字体清单问题自定义图标字体在pubspec.yaml里声明了但运行时图标不显示。排查顺序是先看assets/fonts路径对不对再看family字段是否和代码里fontFamily完全一致最后确认字体文件本身格式是否为ttf且包含对应码点。有时候Android上能用的otf字体在OpenHarmony上渲染成方块换ttf格式立刻就好了。6.3 构建任务依赖解析失败的排查思路用hvigor构建时偶尔会遇到类似“could not determine the dependencies of task”的错误OpenHarmony上通常是ohos模块的依赖解析问题。这次跟Android的Gradle依赖冲突不一样hvigor的依赖解析对网络和仓库地址更敏感。第一反应是检查ohos/oh-package.json5里的依赖版本是否与SDK版本匹配特别是ohos/hypium测试框架和ohos/hvigor-ohos-plugin。这两个组件版本跟API版本强绑定写错一个字母就会导致整个依赖树解析失败。第二是检查网络。OpenHarmony的依赖仓库在gitee上部分地区访问不稳定。如果构建日志里出现connect timeout或者unresolved dependency多试几次或者配置镜像源。这个属于环境问题不是代码问题先别急着改代码。第三是检查模块目录结构。entry/src/main目录下的module.json5、abilities配置影响任务依赖如果某次合并代码时把module.json5改成非法JSONhvigor会报一个看不懂的“task dependency”错误实际就是配置文件解析失败。用DevEco Studio打开配置文件看有没有红波浪线比看堆栈直观得多。6.4 PlatformView与摄像头等系统能力的适配问题分类管理本身不需要摄像头但生活助手App后续要接入扫码记账、拍照识别票据这里提前说一下PlatformView的坑。Flutter在OpenHarmony上的PlatformView机制跟Android上类似也支持混合合成Hybrid Composition但性能表现有明显差距。我测试过在列表页里嵌入一个相机预览OpenHarmony上滑动列表时预览画面会卡顿而且相机画面的旋转方向跟Android相反前置摄像头取景经常是倒的。如果业务上也遇到这个问题排查思路是先用Texture方式渲染如果不行再切AndroidView的混合合成模式同时检查设备传感器方向配置是否在module.json5里声明了orientation。这个问题没有通用解决办法每家设备的表现都可能不一样只能真机逐个调。6.5 上架前的兼容性验证XTS与多设备适配最后提一下OpenHarmony的XTS认证。如果应用要上架到官方应用市场或者在企业内部大规模分发通常需要过XTS兼容性测试。这个测试会验证应用在不同设备上的兼容性表现包括API调用、权限使用、资源加载等。我在分类管理功能上遇到过一个XTS相关的问题测试用例里会遍历应用的每个页面检查是否存在内存泄漏或未释放的资源。由于分类弹窗用了showDialog且没在关闭时正确销毁Controller导致某台测试设备上弹窗多次开关后内存明显上涨。后来我在dispose里把所有TextEditingController和FocusNode都释放掉才过了测试。多设备适配方面OpenHarmony的设备类型差异很大从手机到平板到开发板屏幕尺寸和像素密度都不一样。分类列表在手机上一个ListView就够但在平板上会显得很空。我的处理方式是按屏幕宽度判断超过600dp时切成两列GridView复用同一个数据源和Repository。这个逻辑用在真机上验证过体验比单一列表好不少。写在最后的经验打包这些是在OpenHarmony真机上反复折腾后留下的几条硬经验。第一版本一切以“能跑通空工程”为基准不要追新。我见过太多人非要装最新的Flutter ohos分支然后被一堆编译错误淹没。第二数据层和UI层一定要解耦分类这种看似简单的功能将来加字段、加统计、加云同步都是很自然的需求Repository模式能让你不用推翻重写。第三真机比模拟器重要一百倍OpenHarmony的模拟器在UI渲染和输入法行为上与真机差异巨大凡是涉及拖拽、弹窗、键盘的调整都值得提前插上真机测一测。最后分享一个小技巧调试分类列表刷新问题时可以在Riverpod的StateNotifier里临时加一句print(state.map((c) c.name).toList())每次增删改后看输出顺序是否符合预期。这比在UI层打断点快得多因为很多刷新异常根本到不了UI就已经错了。整个项目做下来我对Flutter在OpenHarmony上的成熟度比一开始乐观了不少——它确实还带着不少工程期的小毛病但应付生活助手这类常规应用场景已经完全够用而且一套Dart代码跑遍Android、iOS、OpenHarmony这件事对中小团队来说太有吸引力了。
返回列表