鸿蒙开发天亮了:codex两天做完一个Flutter项目的迁移
这是一篇真实的 Flutter 到 HarmonyOS / OpenHarmony 迁移复盘:从迁移前分析,到工具链、白屏、MissingPlugin、WebView、图片选择、签名上架,再到最后沉淀出一套可复用迁移 Skill。
skill的git仓库 https://gitee.com/hfqf1234/figo-flutter-harmonyos-migration-skill
先说结果
这次迁移最让我意外的,不是“鸿蒙版本终于跑起来了”,而是整个过程推进得非常快。
从可见提交记录看:
-
某天上午
09:06,开始出现第一批 OHOS 迁移提交。 -
某天下午
14:31,核心鸿蒙功能迁移完成。 -
核心迁移跨度约 5 小时 24 分钟。
-
第二天下午
13:15,进一步把迁移经验沉淀成可复用 Skill。 -
从核心迁移启动到 Skill 沉淀,整体跨度约 28 小时 8 分钟。
最终跑通的不是一个空壳 Demo,而是已有 Flutter App 的真实业务链路:启动、登录、首页、客户列表、本地缓存、WebView、图片选择、拍照、发布包、应用市场问题处理,以及权限合规补充。



一开始,我就没把它当成“重写”
很多人听到“适配鸿蒙”,第一反应是:是不是要重写一套?
如果放在去年,我可能也会犹豫。
那时候很多链路还没有现在这么顺,遇到插件不支持、平台工程报错、原生通道缺实现,往往要靠人一点点翻文档、试版本、猜边界。迁移不是不能做,但过程会更重,也更容易卡在某个细节里。
今年明显不一样。
一方面,AI 开发能力让排查过程变得连续。Codex 可以读工程、看日志、找调用链、改代码、跑验证,再把处理过程沉淀成文档和 Skill。很多过去需要来回切换上下文的工作,现在可以在同一条迁移线上持续推进。
但另一方面,也是更核心的一点:Flutter 生态本身已经给了迁移足够好的底座。
如果一个 Flutter 项目已经把 UI、路由、状态、网络、国际化、主题、业务模型和大部分业务逻辑沉淀在跨平台工程里,真正应该做的就不是重写页面,而是先确认一件事:
现有业务代码能不能继续复用?平台差异能不能被压到足够底层?
这次项目的基础还不错:页面、路由、状态管理、网络层、本地缓存、上传、平台能力,都已经有一定抽象。也就是说,鸿蒙迁移的主线不是把每个页面重做一遍,而是在 Flutter 生态已经提供的复用基础上,把那些“不适合直接跨平台”的部分补上:
-
工具链。
-
平台工程。
-
Flutter 插件缺口。
-
本地存储。
-
WebView。
-
图片选择和拍照。
-
权限说明。
-
签名和发布包。
这个判断很重要。
一旦方向是“复用业务 + 补平台能力”,迁移就不再是无边无际的重写,而是一组可以被拆解的问题。
真正提速的是迁移前分析
这次迁移能推进得快,并不是因为一开始就直接开干。
相反,真正节省时间的,是动手前先做了一轮迁移分析。
当时先拆了几个问题:
-
当前 Flutter 项目能不能直接生成
ohos/平台工程? -
Flutter / Dart / 依赖约束是否匹配 OHOS Flutter?
-
哪些依赖是纯 Dart 或纯 UI,风险很低?
-
哪些依赖需要 OHOS 插件实现,风险中等?
-
哪些能力强依赖原生 SDK、FFI、设备能力,必须专项处理?
-
代码里有没有 Android / iOS 专属 import、MethodChannel、平台字段、权限申请和 SDK 初始化?
-
首版到底要保留哪些功能,哪些可以先降级,哪些可以暂缓?
这一步很像迁移前的地形扫描。
如果不先做这件事,很容易一上来就掉进某个插件坑里,然后忘了迁移的主目标其实是:先让业务主链路跑起来。
最后迁移路线被拆成了几个阶段:
P0:空壳工程与构建验证
P1:核心编译适配
P2:核心业务闭环
P3:平台能力补齐
P4:签名、包体和上架
这样做的好处是,每一阶段都有自己的目标,不会让后面阶段的问题提前阻塞前面阶段。
比如蓝牙打印、推送、扫码、崩溃上报这些能力都重要,但它们不应该阻塞“应用能启动、能登录、能进入首页、核心列表有数据”。
这就是速度的来源之一:不是把所有问题同时解决,而是把问题放回它应该出现的阶段。
第一关:工具链隔离
鸿蒙迁移的第一个坑,不在代码里,而在工具链里。
Android / iOS 仍然要使用官方 Flutter,鸿蒙则需要 OHOS Flutter。如果直接把 OHOS Flutter 覆盖原来的 Flutter 环境,很容易把已有发版链路搞乱。
所以第一步就是隔离:
-
官方 Flutter 继续服务 Android / iOS。
-
OHOS Flutter 单独安装。
-
DevEco Studio 和 HarmonyOS SDK 单独配置。
-
用项目级脚本临时切换环境。
这一步看起来不性感,但它决定了后面能不能安心往前冲。
因为只要 Android / iOS 发版链路不被破坏,鸿蒙迁移就可以大胆试错;出了问题,影响范围也只在 OHOS 构建链路里。
【图片占位 4:工具链或构建命令截图】
第二关:先让它构建
生成 ohos/ 平台工程之后,马上进入构建问题。
这类问题通常很杂:Dart 版本、Flutter SDK、DevEco API、Hvigor、OHPM、HAR、HAP、第三方依赖,每一个都可能卡住。
这次遇到过两个典型问题:
一个是 Dart / Flutter 版本不匹配。旧的 OHOS Flutter 分支带的 Dart 版本太低,无法满足现有 Flutter 工程约束,只能切换到更合适的 OHOS Flutter 版本。
另一个是 DevEco SDK API 兼容问题。Flutter OHOS embedding 使用了更高 API 的 Autofill 类型,而当前 SDK 编译不过。最后的处理方式不是手工改一次算一次,而是把补丁沉淀成脚本,让构建前可以重复执行。
这个经验很朴素:
迁移过程中,凡是会重复踩的构建坑,都要脚本化。
一次手工修改是救火;脚本化之后,才算进入工程化。
第三关:能安装,但白屏
构建通过之后,并不代表应用能跑。
模拟器里打开应用,白屏。
这类问题最容易让人焦躁,因为它不像编译错误那样明确告诉你哪一行挂了。白屏只是在告诉你:Flutter 树没有正常挂载,或者首帧之前某个初始化卡住了。
排查顺序就变得很关键:
-
runApp()有没有执行。 -
首帧前有没有平台调用。
-
系统栏、方向、插件初始化有没有在 OHOS 上阻塞。
-
隐私协议、登录态恢复、推送、崩溃上报是不是太早执行。
最后定位到系统 UI 配置在 OHOS 启动阶段存在阻塞风险,于是在鸿蒙平台跳过相关 SystemChrome 调用,让 Flutter Widget 树先挂载。
这一步跑通后,登录页终于出来了。
看到登录页的那一刻,迁移就从“理论上可行”变成了“可以继续打穿”。
第四关:MissingPlugin 不是偶发,是必经之路
登录时很快遇到了经典错误:
MissingPluginException(No implementation found for method getAll on channel plugins.flutter.io/shared_preferences)
这不是某个小 bug,而是 Flutter 迁移鸿蒙时非常核心的一类问题:
Flutter 插件在 Android / iOS 上可用,不代表在 OHOS 上也有实现。
shared_preferences 如此,安全存储如此,很多平台能力都如此。
处理思路不是在业务页面里写一堆 if 判断,而是回到底层抽象:
-
普通 KV 存储先做 OHOS 兜底。
-
安全存储先保证登录链路能走通。
-
长期方案再接鸿蒙安全存储能力。
这里有一个取舍:早期为了验证主链路,可以接受某些能力先降级;但必须在文档里写清楚这是 P0/P1 方案,不要把“临时兜底”误认为“长期实现”。
第五关:客户列表没数据,问题不是“鸿蒙没有 SQLite”
客户管理列表进入后没数据。
第一反应很容易是:是不是鸿蒙没有 SQLite?
后来确认,这个判断不准确。
鸿蒙系统本身有关系型数据库能力,可以通过 RDB 执行 SQL。真正的问题是 Flutter 侧原来的 drift + sqlite3 + sqlite3_flutter_libs + path_provider 这一套链路,在 OHOS 上没有完整打通。
所以解决方案不是放弃本地缓存,而是换一条路:
-
Flutter 业务层继续依赖缓存抽象。
-
Android / iOS 继续使用原来的 Drift 实现。
-
OHOS 侧通过 ArkTS 插件桥接系统 RDB。
这样一来,客户列表、登录后同步、本地搜索、车牌/VIN 查客户这些业务路径,都不需要大面积改页面。
这一步给我的经验很深:
插件不可用,不等于系统能力不存在。
迁移时不要只盯着 Flutter 插件,要往下看一层:系统有没有原生能力?能不能通过 MethodChannel 或 ArkTS 插件桥接?业务层能不能继续保持干净?
第六关:WebView 要从 Android 依赖里解耦
工作台顶部 H5、隐私政策、用户协议、报表页面,都依赖 WebView。
这类页面在业务上看起来只是“打开一个 H5”,但工程上常常埋着 Android 专属配置。如果 Dart 文件里直接 import Android WebView 实现,OHOS 编译就会失败。
所以先做了一层兼容收口:
-
页面不直接依赖 Android WebView 类型。
-
Android 专属配置放进兼容层。
-
OHOS 接入自己的 WebView 实现。
最后工作台顶部 H5 能打开,协议页能打开,说明核心 H5 容器链路打通了。
这类问题的关键词还是一个:边界。
跨平台迁移最怕页面里到处散落平台细节。一旦平台差异被收口,后面换实现就轻很多。
【图片占位 5:工作台顶部 H5 在鸿蒙端运行截图】
第七关:图片选择、拍照和上传
图片能力是业务 App 很难绕开的部分。
客户头像、反馈附件、商品图片、车辆照片、门店图片、OCR 图片,背后都需要相册或相机。
OHOS 下如果没有现成插件,就自己补 ArkTS 插件:
-
打开系统图片选择器。
-
获取用户选择的图片 URI。
-
复制到应用 cache 目录。
-
返回 Flutter 可读取的本地路径。
-
继续复用原有压缩、上传、回填流程。
这一步的关键不是“写了一个图片插件”,而是让所有图片入口继续走统一 Image Gateway。
这样未来再补相机、压缩、权限、上传失败处理,只需要在能力层增强,不需要每个页面单独补一次。
【图片占位 6:图片选择或反馈附件截图】
第八关:能上架,还要能过审
技术迁移跑通后,还有发布迁移。
鸿蒙市场提交的不是 HAP,而是 .app。签名、profile、bundleName、设备类型任何一项不匹配,都可能报错。
迁移过程中遇到过几类问题:
-
上传包不是 HarmonyOS 应用后缀。
-
非法软件包。
-
包名与应用不匹配。
-
设备类型需要支持手机、平板、PC/2in1。
这些问题没有什么捷径,就是按发布链路逐项校验:
-
确认
.app产物。 -
确认证书和 profile。
-
确认 bundleName 与后台一致。
-
确认设备类型。
-
确认没有手工拆包破坏签名。
还有一个很容易被忽略的问题:权限合规。
应用审核反馈相机权限申请时,没有同步告知使用目的。这个问题不是隐私政策里写了就够,运行时申请权限前也要明确告诉用户:申请什么权限、用于什么功能、做什么用途,并且说明不能自动消失。
最后我们把权限用途说明统一放到权限服务里,而不是散落在页面里。这样客户反馈拍照、头像、车辆照片、商品图片、OCR 等入口,都能被统一覆盖。
为什么能这么快?
我复盘了一下,这次能在空闲时间里快速推进,主要不是因为“鸿蒙迁移很简单”,而是因为没有一开始就陷入重写。
真正提升效率的是几个判断:
1. 先分级,再动手
迁移前先把依赖和能力分级:
-
低风险:纯 Dart、纯 Flutter UI、模型、日期格式、状态管理,优先保留。
-
中风险:本地存储、权限、WebView、图片选择、外链、分享,需要查 OHOS 适配或做降级。
-
高风险:SQLite 原生链路、扫码、蓝牙打印、推送、崩溃上报、地图、支付、厂商 SDK,单独专项处理。
这个分级让迁移不会被“所有东西看起来都有风险”吓住。
低风险直接前进,中风险找替代,高风险放进专项计划。节奏一下就清楚了。
2. 先打主链路,不追求一步到位
第一目标不是完美,而是:
-
能构建。
-
能启动。
-
能登录。
-
能进入首页。
-
核心列表有数据。
-
关键页面能打开。
主链路通了,后面每个问题都有落点。
3. 页面尽量不动,平台能力往底层收
如果每个页面都加 OHOS 判断,迁移会很快失控。
这次更有效的方式是:
Flutter 页面 -> 业务 Controller -> 平台网关 -> Android / iOS / OHOS 实现
页面只关心“我要选图片”“我要打开 WebView”“我要读缓存”,不关心底层是 Android 插件、iOS 插件,还是 OHOS ArkTS 插件。
4. 把临时方案和长期方案分开
有些地方为了快速验证,可以先降级,比如登录态内存兜底。
但必须明确写出来:
-
这是为了跑通 P0/P1 主链路。
-
它不是长期安全存储方案。
-
后续要替换成正式鸿蒙能力。
这个边界能避免后续技术债变成“没人知道为什么这么写”。
5. 每个坑都要沉淀成检查项
构建坑沉淀成脚本。
发布坑沉淀成清单。
权限坑沉淀到统一服务。
平台能力坑沉淀到网关抽象。
这些东西不只是为了这次迁移,也是为了下一次升级 Flutter、升级 DevEco、重新打包、重新过审时,不再从零开始排查。
最后沉淀:一个 Flutter 鸿蒙迁移 Skill
这次迁移结束后,我没有只留下一份复盘文档,而是把方法进一步提炼成了一个可复用的 Skill:
figo-flutter-harmonyos-migration-skill
它主要覆盖:
-
Flutter 到 HarmonyOS / OpenHarmony 的迁移前可行性评估。
-
低 / 中 / 高风险依赖分级。
-
Android / iOS 平台耦合点扫描。
-
P0-P4 迁移路线和阶段验收标准。
-
首版功能保留、降级和暂缓取舍。
-
官方 Flutter 与 OHOS Flutter 工具链隔离。
-
ohos/平台工程生成和检查。 -
第一轮构建命令和构建阻塞排查。
-
白屏和首帧问题定位。
-
MissingPluginException处理思路。 -
本地存储、SQLite/RDB、WebView、图片选择、拍照适配。
-
权限用途说明和应用市场合规。
-
HAP、HAR、HSP、
.app、签名、bundleName、设备类型检查。 -
迁移后的验证清单。
里面还放了两个参考脚本:
scripts/harmonyos_flutter_env.sh
scripts/patch_flutter_ohos_api24_autofill.sh
一个用于展示如何局部切换 OHOS Flutter / DevEco 工具链;另一个用于展示如何把确认过的 SDK 兼容补丁沉淀为可重复执行的构建前脚本。
我觉得这件事比“这次迁移成功”更重要。
因为真正有价值的工程经验,不应该只停留在某一次问题解决里。它应该被压缩成下一次可以直接调用的方法。
写在最后
这次 Flutter 鸿蒙迁移给我的最大感受是:
速度不是靠莽出来的。
速度来自迁移前分析,来自风险分级,来自边界清楚,来自先主链路后细节,来自把平台差异压到底层,来自每解决一个坑就顺手把它变成脚本、清单或 Skill。
从某天上午 09:06 到当天下午 14:31,核心迁移跨度约 5 小时 24 分钟。
从开始迁移到沉淀出 Skill,整体跨度约 28 小时 8 分钟。
放在连续工作里,这个数字已经不错;放在空闲时间里,它更说明一件事:
只要架构边界足够清楚,AI 协作足够聚焦,Flutter 到鸿蒙的迁移完全可以比想象中更快。
下一次再遇到类似迁移,我不会从“怎么开始”重新想一遍。
我会直接打开那份 Skill。
更多推荐



所有评论(0)