☰
Flutter for OpenHarmony跨端通信:衣橱管家设置功能全解析
2026/10/3 3:50:03 网站建设 项目流程

做个衣橱管家App,我本来是冲着首页那堆花活来的:衣物瀑布流、拍照识别分类、天气搭配推荐。结果几周折腾下来,真正让我反复跟“设置”二字死磕的,反而是页面最不起眼的那一排开关——主题、字体、通知、备份,每一个都像一面镜子,照出Flutter for OpenHarmony这套组合里跨端通信的底子。

这套项目的技术栈用的是Flutter for OpenHarmony,也就是OpenHarmony-SIG维护的flutter_flutter社区分支,把Flutter的UI层整体跑在鸿蒙的Ability和GPU生态上。衣橱管家App本身要解决的是“今天又不知道穿什么”这个经典难题:录入每件衣物,给它们贴上品类、季节、场合标签,存进OpenHarmony本地数据库,再根据天气和场景给出搭配建议。而设置功能要做的事比表面看上去多得多:主题模式、字体大小、通知推送、数据备份、缓存清理。这些配置项看着都不复杂,但挂在鸿蒙原生系统之上,每一个开关背后都牵扯到Flutter层和OpenHarmony层之间怎么通信、怎么持久化、怎么恢复。

这篇文章专门记录设置功能从零到上线的全过程,适合准备把Flutter项目往OpenHarmony上迁移的开发者,也适合第一次接触组件通信、MethodChannel、EventChannel的人。文章里所有代码都是我实测下来能跑的版本,文末还有我踩过的几个坑,照着能少走弯路。

1. 项目整体设计与思路拆解

1.1 衣橱管家App的定位与设置模块的角色

衣橱管家这类工具App,核心价值就是帮用户把“衣橱”变成“数据”。每件衣服有照片、品类、季节、购买价格、穿着次数,再叠加天气和场合标签,就能给出一套搭配建议。用户每天打开App看“今天穿什么”,本质上是看一个推荐结果,而推荐结果依赖的基础数据质量,又取决于录入和分类是否顺手。

设置功能在这种App里的角色比较特殊:它不与用户每天的核心动作直接相关,却又不能被忽略。它是用户偏好的集中出口,也是App可用性的最后兜底。比如深色模式,用户如果不喜欢刺眼的亮色,但又找不到开关,大概率直接卸载;比如字体大小,给中年用户或有视力障碍的用户调到特大号,是最基本的人文关怀;再比如数据备份,衣橱数据是用户一点点拍照录进去的,一旦换机或者误删,没有备份等于白干。

所以我把设置模块定位成“低频但长尾”的核心页面。低频是指访问次数少,长尾是指每一个功能点都要长期稳定运行,出问题的影响面比首页更大。这个定位直接影响技术方案:设置页不允许有阻塞性操作,不允许因某个原生能力缺失而整页白屏,更不允许切走页面再回来时状态全丢。

1.2 为什么选Flutter for OpenHarmony而不是纯ArkUI

项目选型阶段,团队里有人建议直接用OpenHarmony的ArkUI写整套App,理由是官方支持、生态链完整。我没有立刻否定,但列了几条对比:

第一,团队已有Flutter经验。把现有的Flutter代码迁移到OpenHarmony社区分支,学习成本远低于让所有人从零学ArkTS加声明式UI。第二,跨端一致性。衣橱管家App未来大概率要同时发Android和iOS版本,Flutter一套UI三端跑,维护成本明显更低。第三,UI渲染密度。设置页这种大量列表项、开关、留白和圆角卡片的界面,用Flutter的组件体系写起来比ArkUI手搓快得多,尤其是我这种已经习惯了Flutter布局模型的人。

当然,Flutter for OpenHarmony不是没有代价。社区分支的迭代节奏落后上游Flutter SDK,第三方插件生态基本要靠自己适配,MethodChannel和EventChannel这些通信接口的稳定程度也比官方平台差一些。但这些代价集中在“接入期”,一旦通道铺好,开发效率和跨端收益会迅速覆盖前期成本。

1.3 设置功能的技术拆解:三层各管什么

我把设置功能拆成三层,每一层的职责边界画得很清楚:

  • Flutter UI层:只管展示和交互。列表项、开关、弹窗、分组标题,全部用Flutter自绘组件完成,不引入任何鸿蒙原生控件。这样做的原因很简单:一套UI代码三端复用,而且可控性最好。
  • Dart状态层:管配置项的读写和分发。设置项的当前值、变更通知、持久化读写,都通过一个全局的SettingsController管理。无论是主题切换还是字体缩放,UI层只跟Controller对话,不直接操作存储。
  • 原生通信层:管Flutter层碰不到的系统能力。读取系统深色模式切换事件、控制通知开关、调用系统备份目录,这些必须通过MethodChannel或EventChannel桥接到OpenHarmony原生侧。

这个三层划分在后续开发中帮了大忙。比如做字体缩放时,UI层只需要监听Controller里的textScaleValue,完全不知道底层是SharedPreferences还是别的存储方案;做通知开关时,Controller只需要调一个Future方法,完全不用关心鸿蒙原生侧的通知API叫什么名字。每一层都能独立测试,出问题也能快速定位。

2. 设置页界面结构与交互设计

2.1 分组列表的结构设计

设置页的UI结构我参考了主流App的分组方式,没有走过于新颖的视觉路线。原因很朴素:设置页的用户目标明确,就是在最短时间内找到想改的项,创新设计反而增加认知负担。

页面用ListView承载,分为五个逻辑分组:外观、通知、数据管理、通用、关于。每个分组有一个轻量级标题,下面挂对应的条目。外观组放深色模式、字体大小、动态字体开关;通知组放搭配提醒、换季提醒、清洁提醒三个开关;数据管理组放自动备份、立即备份、恢复数据、清除缓存;通用组放语言、震动反馈、减少动效;关于组放版本号、开源许可、意见反馈。

用Flutter实现这种结构,最稳的方案是一个带section header的列表。我写的是ListTileswitchTileRadioListTile,配合一个简单的分组组件:

class SettingsSection extends StatelessWidget { final String title; final List<Widget> children; const SettingsSection({super.key, required this.title, required this.children}); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 4), child: Text( title, style: Theme.of(context).textTheme.labelMedium?.copyWith( color: Theme.of(context).colorScheme.primary, ), ), ), Card( margin: const EdgeInsets.symmetric(horizontal: 12), child: Column(children: children), ), ], ); } }

有人可能会问,为什么不直接用一个简单的ListView然后把所有条目平铺,非要花心思做分组。我实测下来,分组至少在两个地方有优势:一是用户扫视速度更快,眼睛能直接定位到“数据管理”“关于”这类关键词;二是条目之间的层级关系更明确,避免一大屏开关看起来像一个控制面板。唯一的代价是代码量多一点,但对于设置页这种规模,代价完全可以接受。

2.2 滚动、刷新与交互细节

设置页通常会遇到两个滚动场景:一是列表项太多,屏幕装不下;二是清除缓存或恢复备份后,页面上的状态要刷新。第一个场景用ListView天然解决,但第二个场景需要配合刷新机制。

我给设置页包了一层RefreshIndicator,下拉刷新时重新读取部分原生状态(比如备份时间、缓存大小)。这个交互不一定在所有App里都需要,但衣橱管家App的数据管理组有“备份状态”这类动态信息,下拉刷新是最符合用户直觉的交互。代码很简单:

RefreshIndicator( onRefresh: _refreshState, child: ListView( physics: const AlwaysScrollableScrollPhysics(), children: [...], ), )

为了避免下拉手势在Switch上产生冲突,我特意确认了所有开关都是SwitchListTile默认行为,没有额外嵌套手势识别器。这个细节在真机上容易踩坑:有些开发者为了自定义开关样式,会自己包一层GestureDetector,结果在列表里上下滑动时,开关区域经常误触。

另外,设置页里我统一用了系统默认的Switch样式,没有做华丽的动画改造。原因是鸿蒙适配版的Flutter对自定义动画的渲染效率一般,过度追求视觉效果反而会让设置页在低端设备上滑动掉帧。

2.3 页面切换不丢状态的方案

热词里有一条“flutter navigator切换页面后,会丢失状态吗”,这个问题在设置页上特别典型。用户从首页进入设置页,改了主题、改了字体大小,返回到首页时如果主题没有生效、字体没有恢复,体验会非常糟糕。

Flutter的Navigator默认行为是:页面被完全覆盖时,状态还在,但页面在后台可能被GC回收;如果设置了自动释放资源,或者用Tab切换页面销毁了State,那回来就是重建。设置页本身不复杂,关键是它修改的状态要被全局共享,而不是放在设置页自己的State里。

我的做法是把所有设置项收敛到一个全局单例SettingsController里,页面State只负责展示,不负责持有数据:

class SettingsController { final SharedPreferences _prefs; final ValueNotifier<ThemeMode> themeModeNotifier; final ValueNotifier<double> textScaleNotifier; final ValueNotifier<bool> reduceMotionNotifier; ... }

主题、字体大小这些全局状态全部挂在ValueNotifier上,MaterialApp的根Widget监听这些Notifier,一变化就触发生效。设置页切走再切回来时,Widget从Controller里重新读一遍当前值,UI自然正确。

对于首页那些不能丢失的列表位置、滚动位置,我用AutomaticKeepAliveClientMixin保证Tab页面不销毁。这招在处理衣橱照片列表时特别重要,用户翻了三百多件衣服,切到设置页改完字体再切回来,列表还停留在原来的位置,这个细节做不好会被用户反复骂。

3. 核心功能模块的实现与代码解析

3.1 主题模式切换:SharedPreferences加ThemeMode

主题模式是设置页里最直观的功能,但它牵涉的链路比你想象的长。用户点一下“深色模式”,要经历UI变更、存储变更、全App刷新三步,而且如果在OpenHarmony上不开深色模式,默认亮度高得让人眼睛疼。

我把主题模式设计成三个选项:浅色、深色、跟随系统。前两个直接在Flutter侧控制MaterialApp的themeMode,第三个则需要读取OpenHarmony系统当前的深浅色。存储用shared_preferences的鸿蒙适配版,底层落到本地Preferences文件,键名存“themeMode”,值为字符串。

Sandmounted App入口处的代码是这样的:

MaterialApp( theme: _buildLightTheme(), darkTheme: _buildDarkTheme(), themeMode: _settingsController.themeModeNotifier.value, ... )

设置页里的三个选项,我直接用一个RadioListTile的组来展示,用户每次选中都会调用Controller的updateThemeMode方法:

void updateThemeMode(ThemeMode mode) { themeModeNotifier.value = mode; _prefs.setString('themeMode', mode.name); }

这里有三个容易翻车的点。第一,ThemeMode的name方法返回的是“light”“dark”“system”,读取后要转回枚举,转不了就给默认值。第二,保存操作是异步的,不要await后再刷新UI,因为Notifier已经即时更新了,await反而会造成视觉上的卡顿感。第三,用户选择“跟随系统”后,需要立刻根据当前系统模式切换一次主题,不能等下一次系统事件到来,所以我会在Controller的初始化阶段就通过EventChannel向原生侧拉一次当前模式。

3.2 字体大小调节:TextScaler的正确打开方式

App内的字体大小设置,是容易被低估的技术点。很多人觉得“无非就是全局改个字体倍数”,实际做起来会发现,列表项高度、图文混排、富文本都可能因字体缩放而错位。衣橱管家里最典型的是衣物详情页的标签栏,字体放大后标签换行导致卡片高度不一样。

实现思路是在MaterialApp的builder里包一层MediaQuery,用TextScaler.linear做线性缩放:

builder: (context, child) { final textScale = _settingsController.textScaleNotifier.value; return MediaQuery( data: MediaQuery.of(context).copyWith( textScaler: TextScaler.linear(textScale), ), child: child!, ); }

字体档位我设置了三档:标准1.0、大1.2、特大1.35。没有做更细的滑条,因为设置页的需求是“清晰够用”,不是像素级调节。

真正让我折腾了一阵的是与系统字体大小的关系。OpenHarmony系统本身有字体大小调节功能,App如果不去干预,系统设置会直接盖过来,导致App内字体突然变成2.0倍,界面直接崩掉。我的处理方式是做一个“跟随系统字体”的开关,默认关闭,关闭时App固定用1.0倍字体不受系统影响,开启时才去读系统字体倍数。这个开关的默认状态尤其重要,很多用户并不希望手机系统字体一调大,所有App都被迫变大。

3.3 通知开关:MethodChannel调鸿蒙原生能力

通知开关使用的是MethodChannel。Flutter层能做的只是把“开”“关”的意图发给原生侧,真正控制鸿蒙通知服务的代码必须在OpenHarmony的Ability工程里写。

我在Dart侧封装了一个通知服务类,避免每个开关页面都直接抱MethodChannel:

class NotificationService { static const MethodChannel _channel = MethodChannel('com.wardrobe.settings/notification'); Future<bool> setEnabled(String type, bool enabled) async { try { final result = await _channel.invokeMethod<bool>( 'setNotificationEnabled', {'type': type, 'enabled': enabled}, ); return result ?? true; } on PlatformException catch (e) { debugPrint('通知设置失败: ${e.message}'); return false; } } }

为什么要把通知开关放进MethodChannel而不是直接用SharedPreferences?因为用户关闭系统通知权限后,光在App内部改一个布尔值没有任何意义,通知依然会从系统层面被拦截。所以这里需要的不是App内状态,而是真实的系统权限状态,和鸿蒙的通知管理接口打交道是唯一正确的方式。

原生侧的处理逻辑,在OpenHarmony的Stage模型入口(通常是EntryAbility)中注册方法回调,用channel的setMethodCallHandler接收来自Flutter的请求。核心语义就是:取出调用参数,判断是哪个通知类型,调用对应的通知管理接口,最后返回成功或失败。这里必须提醒一句:原生侧代码的具体写法和你用的Flutter for OpenHarmony适配版本强相关,不同版本注册通道的入口可能有差异,最稳的路径是先跑通模板自带的一个MethodChannel示例,再往里套自己的逻辑。我见过不少开发者在不确认模板示例的情况下直接照抄老代码,结果channel注册失败半天查不出来。

3.4 数据备份与恢复:异步任务与进度反馈

数据备份是衣橱管家App设置功能里最“重”的操作。衣橱数据可能包含几百张衣物照片和结构化的衣物属性,备份方案我选择导出为JSON文件加图片目录,压缩后放到App外部存储的应用专属目录,恢复时再反向解析。

备份流程用了一个简单的异步方法,由Controller驱动,UI层通过FutureBuilder或ValueNotifier监听状态:

Future<BackupResult> performBackup() async { setState(() => _isBackingUp = true); try { final json = jsonEncode(wardrobeData.toJson()); final backupPath = await _backupService.writeBackup(json, imageAssets); await _prefs.setString('lastBackupTime', DateTime.now().toIso8601String()); ... } finally { setState(() => _isBackingUp = false); } }

备份过程中我加了一个模态进度框,里面显示“正在备份,请勿关闭App”。这个体验细节是从用户实际场景出发的:备份操作往往伴随着换机或清理手机,如果用户点完立刻切后台,备份可能会中途失败,下次启动时看到数据还是旧的,会产生“这App是不是把我的数据搞丢了”的疑虑。所以进度反馈不仅是一个UX设计,更是对用户预期的管理。

清除缓存的设计也很简单:遍历App缓存目录,删除图片缩略图缓存和临时文件,把总大小重新计算出来。这里的坑是计算缓存大小的任务不能放在UI线程。我一开始图省事直接用synchronous方式遍历目录,结果低端鸿蒙设备上明显掉帧,后来改成Isolate异步计算,设置页的流畅度才恢复正常。清理完缓存后,用RefreshIndicator刷新一下“缓存大小”那行文字,整个交互闭环就完整了。

4. Flutter与OpenHarmony原生通信实战

4.1 MethodChannel与EventChannel配置流程

Flutter组件通信有两条路,一条是主动调用,一条是被动监听。设置功能里恰好两类都用上了。配置流程我总结为四步:

第一步,在Dart侧定义channel名称,创建MethodChannel/EventChannel实例。channel名称全局唯一,推荐用域名倒写加模块名,避免与其他插件冲突。第二步,在原生侧注册同一个channel,名称必须完全一致,包括大小写和点号。第三步,Dart侧发起调用或监听事件流。第四步,原生侧成功或失败时返回结果,错误信息通过PlatformException传递。

MethodChannel的调用模型是双向的,既可以由Flutter调原生方法,也可以由原生侧向Flutter发送结果。EventChannel的模型是单向的,原生侧作为事件源,不断地把事件推给Flutter侧监听器。

一个容易混淆的点是:MethodChannel也能间接实现“原生推数据给Flutter”,比如原生侧保存引用,然后调用channel.invokeMethod把数据传给Flutter。但这不是它的标准用法,因为MethodChannel的invokeMethod在原生侧默认没有广播语义,多个监听者会互相覆盖。EventChannel的receiveBroadcastStream天然支持多订阅者事件分发,语义更清晰。

我在设置功能里的分工是:用户主动操作系统能力(改通知权限、读取备份位置)走MethodChannel;系统环境变化(深浅色切换、字体等级变化)走EventChannel。

4.2 用EventChannel监听系统深色模式切换

衣橱管家App的“跟随系统”主题模式,依赖读取OpenHarmony的深色模式状态。但这个状态在Flutter层不能直接获取,需要原生侧监听系统配置变化,并通过EventChannel推送下来。

Dart侧的监听代码:

static const EventChannel _systemEventChannel = EventChannel('com.wardrobe.settings/system_config'); void _listenSystemDarkMode() { _systemEventChannel.receiveBroadcastStream().listen( (event) { if (event is String) { final isDark = event == 'dark'; if (_settingsController.themeModeNotifier.value == ThemeMode.system) { _settingsController.applySystemMode(isDark); } } }, onError: (Object e, StackTrace st) { debugPrint('系统配置监听失败: $e'); }, ); }

这里有几个容易被忽略的细节。第一,listen之后返回的是StreamSubscription,页面销毁或App进入后台时最好能cancel掉,否则会积累多个订阅。我在Controller里维护了一个订阅引用,在dispose时手动释放。第二,EventChannel的事件流类型在鸿蒙适配版上不一定稳定,我把event先toString再判断,避免类型强转抛异常。第三,如果原生侧在发送事件前没有确认Flutter侧已经准备好了stream监听,事件会丢失。所以我在App启动并完成channel注册后,会主动向原生侧发一个“订阅完成”信号,让原生侧在之后才开始推送系统事件。

原生侧发送事件的逻辑我写成通用伪代码:

// 在系统配置变更回调里 if (isDarkModeChanged) { channel.sendEvent(isDark ? "dark" : "light") }

事件字符串的语义统一用“dark”“light”,不要用0和1,因为0和1在不同设备上语义可能被误读,字符串更直观也更安全。

4.3 通信方案选型对照

做设置功能时,我在三个通信方案之间反复对比过。这里给出一个适合实际项目参考的选型矩阵:

方案适合场景在设置功能中的应用注意事项
MethodChannel主动调用并等待结果修改通知权限、备份数据、触发系统能力channel名必须一致,错误信息用PlatformException携带
EventChannel持续监听系统事件系统深浅色切换、系统字体变化、电量变化防重复订阅,释放订阅流
PlatformView嵌入原生控件设置页内展示系统日历、文件选择器通用性最差,建议设置页少用
shared_preferences本地数据持久化保存主题选项、字体档位、开关状态异步读写在启动时要处理时序

我特意把PlatformView放进表格里,是为了提醒大家:如果有个方案看起来“什么都能做”,那它在设置页里往往是最不划算的。设置页的控件全部用Flutter自绘就好,原生控件嵌入会带来渲染层级复杂、触摸事件冲突、生命周期同步等问题。只有确实需要原生能力(比如用系统文件选择器选备份文件)时才走PlatformView,我的衣橱管家App里备份恢复文件选择确实用了,但只在那个场景用,其他设置项一律Flutter自绘。

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

5.1 构建与依赖阶段的坑

在OpenHarmony上构建Flutter工程,和标准Flutter工程最大的区别是产物格式。标准Flutter打的是APK或AAB,OpenHarmony适配版打的是hap包,构建命令我不在这里写死,因为不同分支命令略有差异,以你本地仓库的README为准。但有几个共性问题值得说:

第一,OpenHarmony的SDK路径必须显式配置,否则构建时Gradle找不到鸿蒙SDK。我遇到的报错是“Unable to locate OpenHarmony SDK”,最后在local.properties里补上了ohos.sdk.dir才解决。

第二,依赖版本要锁死。Flutter for OpenHarmony对依赖版本非常敏感,尤其是有原生代码的插件,比如shared_preferences、path_provider这种,必须用鸿蒙适配分支的版本,不能直接用pub.dev上的最新版。这个坑我踩得很痛:直接用官方最新版shared_preferences,编译过了,运行起来却直接MissingPluginException,因为鸿蒙平台还没有注册对应的插件实现。

第三,第三方插件的鸿蒙适配进度参差不齐。设置功能里我一开始想用社区版的flutter_secure_storage存用户名,结果发现鸿蒙适配版还没有维护。最终妥协方案是用shared_preferences加简单混淆存储,因为衣橱管家App不涉及特别敏感的数据,设置页的本地存储安全等级够用就可以。

5.2 页面切换状态丢失的排查过程

热词里“flutter navigator切换页面后,会丢失状态吗”这条,我在开发期间真的遇到过。具体现象是:设置页调大字体之后,退回首页,Tab页的卡片文字没有跟着变大;再进设置页,发现字体选项还是1.0。

排查过程是这样的:先检查设置项是否保存成功,发现SharedPreferences里的值已经更新了。再检查Controller的Notifier有没有被监听,打日志发现Notifier确实触发了,但首页Tab页的Widget没有响应。最后定位到问题在首页外层用了PageView加自动释放机制,页面在离开可视区后被销毁,新建的页面没有主动从Controller读一次最新值。

修复方式是给首页的几个Tab页用AutomaticKeepAliveClientMixin保持存活,同时在MaterialApp的builder里监听textScaleNotifier,一旦变化就强制setState刷新整棵树。这个问题的本质是Flutter的页面生命周期和全局状态更新之间的配合问题,而不是单一手段可以解决的:全局状态要可订阅,页面要保持存活,两件事都得做。

5.3 字体与深色模式适配问题速查

适配过程中我整理了下面这张速查表,遇到类似问题可以按表排查:

问题现象常见原因解决方案
深色模式下部分文字看不清只设置了浅色主题,深色主题没有完整定义MaterialApp里补完整darkTheme,别只改背景色
跟随系统模式不生效EventChannel没注册或事件流未监听检查原生侧是否成功注册channel,确认订阅时机
字体调大后卡片文字换行破版固定高度容器没有考虑文本缩放用IntrinsicHeight或让卡片高度由内容撑开
系统字体一调大,App布局乱没有关闭跟随系统字体增加独立开关,默认固定1.0倍文本缩放
切到后台再回来主题色不对系统模式变化的事件没有缓存在EventChannel监听里同步更新本地记录

每一行都是真实踩坑换来的。尤其是第四行,系统字体调大导致布局崩掉,这个问题在OpenHarmony设备上特别常见,因为用户换机后系统字体往往继承了旧手机的设置,比例可能是1.5甚至2.0。如果不做“固定字体倍数”这个兜底开关,App会在一部分用户那里直接废掉。

5.4 性能与包体控制

设置页本身不重,但衣橱管家App的首页承载着大量图片,所以我在优化时不能只看设置页,而是看整个App的平稳性。设置功能引入的MethodChannel和EventChannel对性能影响非常小,真正需要控制的是渲染和存储。

第一,减少不必要的动画。设置页的开关切换、卡片进出动画我都控制在300毫秒以内,并且用animatedOpacity和AnimatedSwitcher这类轻量控件,避免每次都触发整页重建。对于“减少动效”这个设置项,我把它做成了全局开关,开启后App内的页面过渡动画直接关闭,这种细节对老年用户非常友好,但很少有App去做。

第二,控制缓存清理的粒度。衣橱管家App的图片缓存分成原图和缩略图两级,缩略图缓存是最耗空间的,但清理原图缓存会导致离线浏览时图片加载慢。我在设置页把“清除缩略图缓存”和“清除原图缓存”分成两个条目,让用户自己选择,而不是一键全清,这个取舍来自真实用户场景。

第三,包体控制。Flutter for OpenHarmony的包体本来就比纯ArkUI工程大,设置页没有引入额外的图标库和大型依赖。图标全部用Material内置Icons,数据备份用系统自带的jsonEncode和压缩库,没有为一个小功能单独引第三方包。最终hap包控制在预期范围内,用户下载成本没有成为负担。

6. 写到最后的一点心得

设置功能做完,我最大的体会是:在Flutter for OpenHarmony上,真正难的往往不是Flutter本身,而是Flutter层和鸿蒙原生层之间那条通路。MethodChannel和EventChannel学起来不难,难的是意识到“这个功能到底该放哪一层”,以及“原生侧遇到错误时,Flutter层该怎么优雅降级”。设置页恰好是练习这套判断力的最佳场景,功能都是小功能,每一项都能逼你去想:这到底是UI问题、状态问题,还是系统能力问题。

如果你也是第一次把Flutter项目往OpenHarmony上迁,我的建议是从设置功能入手,先把主题、字体、通知这几个单项摸熟,再扩展业务页面。这样试错成本最低,也能最快理解Flutter for OpenHarmony的脾性。最后再分享一个小技巧:把channel相关的调用都封装在一个独立的service类里,不要散落在各个页面。这样无论将来适配新版鸿蒙还是排查问题,你只需要改一个文件,而不是像抓蝴蝶一样满项目找channel调用点。

衣橱管家App的设置功能,只是整个产品的一个侧面。但恰恰是这个最不起眼的模块,帮我把Flutter for OpenHarmony的通信链路彻底打透了。后面再做首页、衣橱列表、搭配推荐时,我心里对“哪些活该Flutter干、哪些活该鸿蒙干”这份账目,已经清清楚楚。

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

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

立即咨询