尧图精选

Flutter鸿蒙适配实战:记账本三端统一与原生桥接踩坑指南

🕒 发布时间:2026/9/8 14:39:22 📁 来源:尧图网络
记账本是移动端最经典的“入门实战”项目但一旦加上“同时兼容鸿蒙”这个前缀工程的隐蔽复杂度立刻翻了几倍。我前阵子刚好把一款基于 Flutter 的记账应用从 Android/iOS 扩展到了鸿蒙设备从环境配置、工程结构、核心账本功能实现到原生能力桥接、HAR 封装、真机调试完整路径走下来之后有不少值得沉淀的东西。这篇文章不聊虚的只讲我在项目里做了什么、为什么这么做、踩了哪些坑、最后怎么解决。如果你正打算用 Flutter 统一三端或者已经在给 Flutter 应用做鸿蒙适配这篇的内容应该能帮你省下不少试错时间。1. 项目选型复盘记账本这类工具应用为什么适合 Flutter 鸿蒙1.1 记账应用的真实技术诉求不是炫技而是低成本多端交付记账类 App 的页面其实不复杂无非是账单列表、记账弹窗、分类管理、统计报表、设置页这几个核心模块但业务细节极其琐碎。真正折腾人的地方在于金额键盘的交互、分类数据的维护、不同时间维度的统计口径、周期性账单等。一套像样的记账产品开发重心往往不是 UI 动效而是长期的迭代稳定性与数据一致性。如果这时候只有 Android 和 iOS 两端Flutter 的优势早就被验证过了。真正需要决策的是“鸿蒙到底要不要做、怎么做”。我当时看了一圈市面上很多团队的选择是再招一拨 ArkTS 的人重新写一版原生应用。可以理解毕竟鸿蒙原生适配最干净但代价也最直白数据层、状态管理、页面交互全部重来第二遍。而记账本这种工具用户非常在意历史账单不能错乱、跨端数据要一致如果两套代码的逻辑分叉后续维护绝对是一场灾难。我最终选择 Flutter 作为底座目标是一个代码库同时出 Android、iOS、鸿蒙三端。业务层尽量复用只针对鸿蒙的系统能力做一层薄薄的适配层。从结果看这个策略是成立的因为我日常 90% 的改动仍然发生在 Dart 业务层鸿蒙特判逻辑只集中在一个目录里。1.2 Flutter、ArkTS、RN 与 KMP 的横向取舍我把当时认真评估过的四条路线放在一起做了个对比方便你自己判断候选方案UI 复用逻辑复用鸿蒙适配成熟度我当时最大的顾虑ArkTS 原生单独开发低低高等于重新养一个技术栈长期维护成本拉满React Native 鸿蒙适配中中中第三方组件在鸿蒙上的兼容参差不齐Kotlin Multiplatform无高中UI 依然要维护两套收益只覆盖一小半Flutter ohos 支持高高中高部分原生插件无法直接使用需要做桥接层这四个方案里ArkTS 的工程质量上限最高但它是“单点最优”Flutter 的方案不是任何单一平台上的“最优解”却是全局综合成本最低的选择。React Native 和 KMP 更适合有特定生态绑定的团队比如团队已经深度使用 RN或者主要语言是 Kotlin。我们这个项目本身已经有 Flutter 代码资产继续押注 Flutter ohos 分支就是顺理成章的事。这里多说一句技术选型最怕只看“现在能不能跑”更要看“以后谁来维护”。鸿蒙的普及速度不管怎么变化一个能覆盖三端的小团队才是记账类项目的常态配置。1.3 Flutter 跑鸿蒙的底层逻辑理解清楚才不会瞎调很多人以为 Flutter 跨鸿蒙是通过编译器把 Dart 代码转换成 ArkTS其实不是。Flutter 能移植到鸿蒙核心原因是它自绘引擎的架构设计UI 渲染发生在 Flutter Engine 内部和操作系统的原生控件树没有直接关系。Dart 代码跑在自己的运行时里只需要底层把窗口创建、输入事件、纹理渲染、字体管理等系统能力接过来。所以在 OpenHarmony 体系里适配的关键是把 Flutter Engine 编译成鸿蒙能加载的动态库让渲染环境对接方舟的能力接口。社区维护的 flutter_flutter 分支就是围绕这条链路持续迭代的。理解这个原理之后有三个推论能直接指导你的工作第一Flutter 版本不能随便升级。ohos 分支通常会滞后于 Flutter 官方版本遇到新版本发布不要急着跟先看分支是否同步。第二纯 Dart 的 pub 包大概率能在鸿蒙上直接用但凡是调用了 Android/iOS 原生能力MethodChannel、EventChannel、插件注册表的包几乎都需要找 ohos 适配版本否则运行时就会报 MissingPluginException。第三调试时必须分清“Dart 代码逻辑问题”和“鸿蒙端桥接问题”不要盲目怀疑跨平台框架本身这能省下大量排查时间。2. 环境搭建实操Flutter 工具链与鸿蒙侧工程的连接方式2.1 开发鸿蒙 Flutter 应用三套环境缺一不可很多人第一次上手就被环境搞到想放弃这很正常。要跑 Flutter 鸿蒙你至少需要把下面三样东西对齐Flutter SDK要使用带 ohos 支持的分支而不是普通的 Flutter 主分支。主流方式是从 OpenHarmony SIG 的仓库拉取对应版本分支或使用官方整合后的工具链。HarmonyOS SDK一般随 DevEco Studio 一起安装。安装后要在系统环境变量里显式指出来例如配置DEVECO_SDK_HOME指向 SDK 目录否则后续构建会一直找不到 target。DevEco Studio它和 Android Studio 的职责类似负责管理鸿蒙侧工程、模拟器和签名信息。如果你只依赖命令行很多调试入口会缺失。以我实际项目为例Flutter SDK 是通过 git 拉取的分支固定下来的。用命令行配置完环境变量后一定要记得新开终端窗口不然flutter doctor看到的还是旧环境。这个细节特别容易坑到刚装完环境的人明明已经改了 path当前终端还残留旧会话于是怎么执行都报找不到命令。建议环境准备好后用flutter doctor -v验证一遍至少能看到 flutter、DevEco、OHOS SDK 的识别情况。如果 doctor 里没有 ohos 相关项那大概率是 SDK 分支或环境变量没有匹配上。2.2 工程结构准备不要把鸿蒙代码混进 Dart 业务里创建 Flutter 工程时仍然用常规命令生成flutter create --org com.example --project-name flutter_ledger ledger_app这个命令默认只会生成 android、ios 等平台目录鸿蒙侧工程通常需要手动集成或通过对应模板工具补齐。我不会把鸿蒙模板文件硬塞进 lib 目录而是保持清晰分界。最终工程结构大概长这样ledger_app/ lib/ core/ db/ theme/ platform/ features/ home/ bill/ stats/ settings/ app.dart android/ ios/ ohos/其中 ohos 目录是鸿蒙侧的壳工程与桥接代码lib 里单独建一个 platform 目录专门存放会和鸿蒙原生交互的封装。给业务层提供的接口是纯 Dart 的抽象类底层具体是走 MethodChannel 还是 EventChannel业务代码完全不需要知道。这样以后如果插件库升级了只需要替换 platform 目录内部实现不会牵连页面层。在开发节奏上强烈建议先把项目在 Android 模拟器上跑通再切到鸿蒙 target。不要一上来就搞三端并行Flutter 业务逻辑本来就一次编写到处运行最大的不确定性只在原生桥接层。Android 能跑通至少说明 Dart 层没问题聚焦去攻鸿蒙桥接即可。2.3 构建与依赖配置镜像、插件兼容清单要提前建立依赖下载和普通 Flutter 项目没有本质区别但国内网络环境下pub 源和 Flutter 存储的访问速度会影响体验。我一般会在项目初始化时配置镜像环境变量export PUB_HOSTED_URLhttps://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URLhttps://storage.flutter-io.cn这只是让依赖下载更快一些不改变任何代码逻辑。真正要重点处理的是插件兼容清单。建议第一天就做一个表格把项目用到的所有依赖列出来标注“纯 Dart 包”还是“含原生代码包”。纯 Dart 的比如 intl、path、collection 这类闭眼用含原生代码的比如 sqflite、shared_preferences、image_picker、flutter_wechat 这类就要逐个验证 ohos 支持情况。我第一版就踩过一次在 Android 侧用得好好的某个统计图表库其实下面挂了一个原生性能检测模块切到鸿蒙之后运行直接闪退。后来把它换成基于 Canvas 自绘的纯 Dart 版本才解决问题。所以在依赖选型阶段提前识别原生依赖能帮你绕开大量隐蔽崩溃。3. 记账本核心模块实现从账本表结构到统计图表的完整落地3.1 数据模型与本地存储账本应用的地基是表设计记账本这个场景数据量一般不会大到需要上服务端数据库但表结构设计仍然不能马虎。我设计的是最常见也最稳妥的三张表分类表、账单表、预算表。分类表负责收入和支出的分类定义账单表记录每笔消费流水预算表按月保存预算金额。以下是实际使用的核心建表语句CREATE TABLE category ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, icon TEXT, type INTEGER NOT NULL, -- 0 支出1 收入 sort INTEGER DEFAULT 0 ); CREATE TABLE bill ( id INTEGER PRIMARY KEY AUTOINCREMENT, category_id INTEGER NOT NULL, amount REAL NOT NULL, type INTEGER NOT NULL, happened_at INTEGER NOT NULL, -- 毫秒时间戳 note TEXT, created_at INTEGER NOT NULL ); CREATE TABLE budget ( id INTEGER PRIMARY KEY AUTOINCREMENT, month TEXT NOT NULL, -- 格式 yyyy-MM amount REAL NOT NULL, UNIQUE(month) );数据库插件这块需要多说一句Android/iOS 上 sqflite 非常顺手但鸿蒙侧的 SQLite 支持目前更稳妥的做法是使用社区适配的方案或者在 Dart 层通过 FFI 调用鸿蒙环境中的 sqlite 库。为了避免后续因为存储层卡住整个项目我在 Repository 之上定义了数据访问抽象底层无论用 sqflite 还是其他实现上层代码都不需要改动。比如账单查询抽象abstract class BillRepository { FutureBill create(Bill bill); Futurevoid delete(int id); FutureListBill queryByMonth(DateTime month); FutureMapString, double queryMonthlySummary(DateTime month); }这套抽象层的价值在后期适配时会被明显放大你绝不会希望“把数据库框架从 A 换成 B”这种操作导致几十个页面跟着改。3.2 状态管理与路由组织让“记一笔”之后全端自动刷新记账应用使用频率最高的路径是打开 App-记一笔-回到列表-看统计。其中隐藏着一个很容易被忽略的细节当用户在记账页插入一条账单后首页列表要更新、当月总支出要更新、统计图表要重新计算。如果用传统 setState 去手动控制涉及跨页面的数据联动时很容易漏刷新。我选了 Riverpod 来做全局状态管理。账单列表、月度汇总这类状态都通过 Provider 暴露任何一笔新增或删除操作执行成功后只需要让对应的 Provider 失效或调用刷新方法全端所有监听该状态的页面都会同步更新。这样做的好处是当页面越来越多时你不需要去维护一张“修改后需要通知哪些页面”的清单状态源是唯一的。路由部分用了 go_router因为记账本后续一定会增加更多二级页面比如账单详情、分类编辑、预算设置。声明式路由比手动 Navigator.push 更好维护尤其在需要深链跳转到某笔账单详情时路径参数直接定义在路由表里清晰得多。3.3 账单录入页的关键交互别让用户输入三次才完成一笔账记账 App 的录入效率直接决定用户留存。我见过不少记账应用用户记一笔账要点五六个控件、输入三个字段极其繁琐。所以在实现账单录入页时我做了几个刻意的设计。第一金额是默认焦点。进入页面后系统键盘自动弹出用户可以直接输入数字节省一次点击。第二分类选择用“网格最近使用优先”的排列方式常用分类排在前面。第三备注不是必填项只有一个低调的输入入口不打断记账主流程。分类选择这里我知道很多 Flutter 新手会用 CheckboxListTile 做多选分类这其实是个伪需求一笔账单只能属于一个分类不应该做多选。但这个组件本身也值得提一下因为在某种设置页上你可能确实需要多选能力。我在做设置页的预算提醒分类时用到过 CheckboxListTile发现默认排版经常控制不住复选按钮和文字之间的距离。我的经验是想微调文字与按钮间距不要直接硬调组件内部可以设置contentPadding或dense属性如果还不能满足就直接用 Row 包一个 Checkbox 加一个 Expanded Text 自定义能控得更细腻。金额输入还有一个容易忽略的边界小数点只能出现一次且输入法必须在某些机型上自动弹出数字键盘。这个我用输入格式化器统一处理用户输入任何非法字符都会在上面拦截。3.4 统计报表模块用图表让用户感知“钱去哪了”统计报表是记账本区别于普通“花销记录本”的核心功能。很多用户记账的目的是月底复盘如果只能看到一条条流水而不是按分类、按月份聚合出来的趋势产品的价值会大打折扣。在图表层次我用了 fl_chart 的折线图和饼图。月度支出趋势用折线图展示分类占比用饼图展示。关键数据不能只靠 Flutter widget 前端算而是要在 SQL 层用聚合查询算好道理很简单如果当月有上千笔账单把原始数据全部 load 到内存再逐条遍历会带来无谓的性能消耗对移动端很不友好。实际用到的按月汇总查询大概是FutureListMonthlySummary monthlySummary() async { final result await db.rawQuery( SELECT strftime(%Y-%m, happened_at / 1000, unixepoch) AS month, SUM(CASE WHEN type 0 THEN amount ELSE 0 END) AS expense, SUM(CASE WHEN type 1 THEN amount ELSE 0 END) AS income FROM bill GROUP BY month ORDER BY month DESC LIMIT 12 ); return result.map(MonthlySummary.fromMap).toList(); }拿到这些聚合数据后前端图表只需要负责渲染性能负担很轻。我实测过 5 年、近 2 万条账单的数据集月度汇总页面秒开这在原生 App 里也是很不错的体验。3.5 设置页与主题细节系统组件主题色也要统一管理设置页通常会用到关于页面、开源许可列表等系统级页面。Flutter 的showLicensePage在开发阶段很实用但它自身的主题颜色经常和 App 主色调不一致尤其是当你的应用用了自定义 ColorScheme 时默认推测的页面颜色可能显得突兀。这里给一个省事方案在设置页跳转时自定义主题作用域给许可页包一层 ThemeTheme( data: Theme.of(context).copyWith( colorScheme: Theme.of(context).colorScheme.copyWith( primary: AppColors.brandGreen, ), appBarTheme: const AppBarTheme( backgroundColor: AppColors.brandGreen, foregroundColor: Colors.white, ), ), child: const LicensePage(), )这样能保证所有跳转过去的系统页面和整体品牌色一致。不要总觉得“反正是系统页面丑一点没关系”用户对记账类应用的信任感很大程度来自细节的一致性。4. 鸿蒙适配实战从权限声明到 HAR 封装的完整步骤4.1 鸿蒙工程的权限声明与基础配置Flutter 应用在鸿蒙上最终会编译成 HAP 包权限声明逻辑和 Android 的 AndroidManifest 类似但写在module.json5里。比如如果记账本需要读取系统图片用来做账单凭据那么要事先在模块配置中声明{ module: { name: entry, type: entry, requestPermissions: [ { name: ohos.permission.READ_MEDIA }, { name: ohos.permission.INTERNET } ] } }这个步骤经常被忽略因为在 Android 上有运行时权限弹窗iOS 上也有使用说明。鸿蒙生态的一些权限策略也遵循类似的“最小化申请”原则。在开发阶段如果你发现系统服务调用没有反应或直接返回错误第一反应应该去查权限有没有声明而不是怀疑代码逻辑。有些接口如果使用系统提供的系统选择器比如拉起系统的图片选择器反而不需要声明存储权限。所以最佳实践是能用系统选择器的就用选择器尽量避免直接读整个媒体库。4.2 通过 MethodChannel 桥接鸿蒙系统能力记账本里我实际用到的一个原生能力是“从系统图库选择一张凭证图”。Flutter 侧通过 MethodChannel 发起调用鸿蒙原生侧在对应的 Ability 或 Extension 中实现方法。核心流程是Dart 侧声明 channel name 与方法名原生侧注册同一个 channel收到调用后使用 PhotoViewPicker 拉起图库选择选择结果拿到 URI 后复制到应用沙箱目录再把新路径返回给 Flutter。这样 Flutter 侧可以把返回路径直接当普通文件处理。这里有三个容易被坑的地方第一channel name 必须完全一致。Android 和鸿蒙侧如果复用了同一套 Dart 代码原生端的 channel name 一点都不能差。第二从图库选出的 URI 不一定能直接读取。要先把源文件拷贝到应用自己的沙箱目录下再返回给 Flutter 用 File 读取否则可能因为持久化权限问题导致图片显示失败。第三如果原生方法没有注册成功Flutter 侧会报 MissingPluginException而不是返回一个空结果。捕获异常并弹出一个友好提示比让用户面对红屏要好很多。const platformChannel MethodChannel(com.example.ledger/picker); FutureString? pickImage() async { try { final String? path await platformChannel.invokeMethod(pickImage); return path; } on MissingPluginException { debugPrint(picker plugin not available on this platform); return null; } }4.3 微信登录等第三方登录在鸿蒙侧的注意事项第三方登录是很多商业应用的刚需。针对热词里有人提到的“flutter 微信登录”我多说一点自己在鸿蒙侧的体会。如果你之前只是在 Android 上做过微信登录千万不要把 Android 的接入逻辑直接平移到鸿蒙。微信在鸿蒙平台有自己独立的 SDK 和接入流程需要去微信开放平台为鸿蒙应用单独申请 AppID 和对应的签名信息AppID 和 Android 侧通常不能复用。如果你的 Flutter 侧选了现成的微信登录插件要确认它是否已经做了 ohos 桥接如果没有就需要自己包一层 MethodChannel。登录成功后的流程和传统平台类似拿 code、换 token、再拿到 unionId 或 openId。潜在风险点在于回调地址和 scheme 配置。鸿蒙侧的拉起与回调机制和 Android 的 intent scheme 有一定差异建议把回调处理都收敛到一个原生模块里而不要让 Dart 层直接管 App 被拉起后的路由逻辑否则排查问题时你会同时面对 Flutter、鸿蒙接入、微信平台三层迷雾。4.4 HAR 封装 so给 Flutter 提供带底层库能力的方法如果你的鸿蒙应用要接入某些专有算法、安全键盘或第三方 SDK通常厂家只会给一个 so 文件这时候就需要在鸿蒙侧封装成 HARHarmonyOS Archive相当于 Android 的 AAR。封装思路是第一步在 DevEco Studio 中新建一个 Library 类型的 Module作为动态库的宿主。第二步把 so 文件按 CPU 架构放进对应目录常见的是libs/arm64-v8a并在构建配置里声明 ABI 支持。第三步在 ets 或 ts 代码里调用该 so 暴露的接口再包一层给 Flutter 调用的 MethodChannel。第四步在 Entry 模块的依赖里加上这个 HAR打包时 so 会被自动带进 HAP。我第一版做的时候直接踩了一个坑只把 so 放到了 Module 工程目录但忘了检查它是否带入了产物。结果真机上运行一调用就崩查了半天是 so 没有打进去。后来验证产物的最简单办法是把打出的 HAP 包解压直接看libs/arm64-v8a下有没有对应的 so 文件。这个检查习惯我一直保留到现在。4.5 模拟器调试与真机验证的节奏开发阶段用鸿蒙模拟器很高效。DevEco Studio 自带模拟器管理可以创建手机、平板等形态。Flutter 侧的 Dart 代码仍可以在模拟器里打断点、看变量、看 Debug 输出。鸿蒙原生侧的代码断点则需要在 DevEco Studio 里执行。这两个断点体系目前还不是同一套 UI新手可能不适应但用熟了之后心里要清楚你当前断的是 Dart VM 还是方舟侧代码。命令行验证也很有用。构建完 debug 包后可以用 hdc 安装hdc install -r entry-default-signed.hap hdc shell aa start -a EntryAbility -b com.example.ledger有一条比较重要的开发经验如果发现安装的包没有包含最新的 Dart 改动先确认构建模式。Release 模式默认不启用 Dart debug 支持很多改动可能没被完整编进去。开发尽量用 debug 构建性能测试再切 release。5. 高频问题排查与避坑技巧实录5.1 版本地狱Flutter SDK、依赖包、鸿蒙分支三方不匹配我遇到过的最典型场景是某天升级了某个第三方依赖然后flutter pub get就一直失败报错信息指向 Dart SDK 版本不满足。因为我的 Flutter SDK 是 ohos 分支版本落后于官方主线新依赖可能要求更高版本。解决思路不是硬 upgrade而是引入 FVM 做多版本管理并把当前分支版本固定在 pubspec 的 environment 和 CI 配置里。依赖升级要谨慎不要逐个去升级优先保证主干依赖处于兼容状态。热词里提到的“flutter 各个版本不对导致依赖包下不下来”本质上也是这一类问题。不要光顾着改 pubspec先看一眼你当前 Flutter 版本很多下载失败是 SDK 版本太低导致解析器直接放弃。5.2 Windows 上构建时报 CMake 找不到 Visual Studio generator如果你在 Windows 上构建含原生代码的插件或鸿蒙适配模块会遇到类似这样的报错CMake Error at CMakeLists.txt:3 (project): Generator Visual Studio 16 2017 could not find any instance of Visual Studio.这个报错的大意是 CMake 尝试用 Visual Studio 作为生成器但在机器上没找到匹配的实例。常见原因是你装了 VS但 C 桌面开发组件没有安装完整或者当前工程配置期望的是旧版本 VS。我的建议是优先确认本机是否具备对应的 C 工具链如果不需要用 MSVC 编译也可以检查当前构建使用的生成器类型涉及 native 模块用 ninja 更简洁。这种问题强依赖于具体插件只能用“先定位是哪个模块触发、再看它要求什么工具链”的思路顺藤摸瓜。5.3 热重载后界面没有刷新的几个原因有朋友问“Flutter 热重载后浏览器没更新”尤其是跑 Web 调试目标时这个问题更常见。现象是改了标题字体颜色点击热重载浏览器页面纹丝不动。先区分两个概念热重载Hot Reload和热重启Hot Restart。热重载保留应用状态只刷新当前页面的 widget但如果你改的是 main 函数、全局变量、路由表顶层结构或者改了 pubspec 和原生代码热重载无效必须热重启才能生效。如果执行了热重启浏览器还是没更新那大概率是 DevTools 附着的调试实例不对或浏览器缓存了旧的 JS bundle。可以把调试 session 断开一次再重新启动。这条经验在 debug 模式下排查 UI 问题特别有用。5.4 UI 细节CheckboxListTile 间距与列表项高度问题合集设置页里一旦用到 CheckboxListTile最容易碰到的问题是复选按钮和文字的间距、右侧留给辅助控件的位置。以下是我实测比较有效的一组调整属性CheckboxListTile( dense: true, controlAffinity: ListTileControlAffinity.leading, contentPadding: EdgeInsets.only(left: 12, right: 12), title: Text(分类名称), value: selected, onChanged: (v) { ... }, )如果对间距有像素级要求可以不用 CheckboxListTile而是自定义 ListTile 的 leading/trailingListTile( leading: Checkbox(value: selected, onChanged: onChanged), title: Text(name), trailing: Text(monthlyAmount), onTap: () onChanged!(!selected), )这种方式的好处是完全掌握布局坏处是要自己处理点击区域。不要怕绕开组件自己拼Flutter 的组件体系本来就鼓励你组合。5.5 高频问题速查表现象可能原因解决思路flutter 命令找不到path 未刷新重开终端确认 SDK 路径依赖下载失败SDK 版本与依赖不兼容用 FVM 锁定版本原生调用报 MissingPluginException插件未做 ohos 桥接检查插件版本或自写 MethodChannel图片选择后无法显示直接拿系统 URI 读取先拷贝到应用沙箱目录热重载无效改到了非 widget 层代码用 Hot Restart 而不是 Hot Reload打出的 HAP 调用 so 崩溃so 没有打入产物解压 HAP检查 libs 目录showLicensePage 颜色突兀未应用自定义主题用 Theme 包裹 LicensePageCheckboxListTile 间距异常默认控件排版限制用 contentPadding/dense 或自定义布局6. 关于这笔技术债我最后想分享的几句体会项目收尾后我回头审视这套 Flutter 鸿蒙的记账本方案最大的体感是真正的成本不在“写业务代码”而在“适应碎片化的系统适配生态”。你始终要面对 Flutter 官方主干、ohos 分支、各 pub 插件维护方、鸿蒙 SDK 版本这几个变量它们不是同步演进的所以版本管理和兼容清单必须从第一天就建立起来。如果你打算做一个尝试性 Demo随时可以上手但如果你要做一个需要上架、长期迭代的产品我建议先花半天时间把所有依赖的鸿蒙兼容性排查清楚。这部分前期规划的投入是最值钱的。后续我会考虑把账本的数据导出、云同步、多设备协同按同样的思路扩展到鸿蒙生态毕竟 Flutter 把三端 UI 拉到了同一起跑线剩下的空间就交给业务想象力了。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →