鸿蒙Flutter框架 0day适配实战:01-背景、分叉仓库、版本命名与 fvm fork 完整安装流程
前言
想在鸿蒙(OpenHarmony / HarmonyOS NEXT)上跑 Flutter 项目,第一道门槛就是装 SDK。与官方 Flutter 不同,鸿蒙版 Flutter 不是 Google 发布的 SDK,而是社区基于上游 Flutter 仓库打补丁维护的分叉——上游即 github.com/flutter/flutter,撰写时上游最新版本为 3.47.8。它有自己的架构改造、自己的仓库、自己的版本命名、自己的安装姿势。
本文是「鸿蒙Flutter框架 0day适配实战」系列的开篇。考虑到背景知识对后续所有篇目都是地基,本篇开头先用一章把背景讲清楚:Flutter 的三层架构长什么样、为什么一个为 Android/iOS 设计的框架「可以」跑在鸿蒙上、社区适配到底做了多少事。背景之后进入本篇主线,回答三个消费侧问题:
- 鸿蒙版 Flutter 该从哪个仓库装?tag 与分支两种形态分别怎么装?
3.44.9+ohos-0.0.1-canary1、3.47.8-ohos-1.0.0这类版本号怎么读?- 怎么装、怎么验证装对了、装不了的时候怎么判断原因?
文中所有版本号、报错信息均取自真实环境实操记录(macOS arm64 + fvm 4.3.1,2026 年 9-10 月),可直接对照复现。
版本口径(2026-10 更新):当前推荐 Flutter OH 适配版 3.47.8-ohos-1.0.0 + DevEco Studio 26.0.0 Release + OpenHarmony SDK/API 26。安装首选 fvm fork 别名直装 tag(
fvm install <别名>/3.47.8-ohos-1.0.0,本篇第五章是完整实测记录);手动 bootstrap 作为兜底路径,见第 2 篇。环境搭建请按 OpenHarmony-flutter 环境搭建指导 操作。
如果你要的是「自己维护 fork、把上游同步过来并发布」,那是生产侧的内容,本系列第 5 篇起展开,本篇只讲到消费侧。
一、背景:为什么会有鸿蒙版 Flutter
1.1 Flutter 的三层架构:只有一层和操作系统有关
先看官方给 Flutter 的定义:Flutter 是一个可扩展的分层系统,上层组件各自依赖下层组件,且不能越权访问更底层。官方架构概览见 docs.flutter.dev 架构文档。这条「不能越级」的规定听起来像洁癖,其实是「能不能适配新平台」的关键:每一层的边界清清楚楚,换掉最底层,上面三层根本感觉不到。

上图左侧是官方分层模型(App → Framework → Engine → Embedder → 操作系统),右侧是每一层源码在哪、产物是什么、鸿蒙动没动——这张表就是后面所有工作量的坐标系:
| 层 | 实现语言 | 源码位置 | 产物形态 | 鸿蒙适配 |
|---|---|---|---|---|
| 框架层 Framework | Dart | packages/flutter*/lib | 随 App 一起编译,无独立二进制 | 改平台分支(本系列后文 421 文件) |
| 引擎层 Engine | C++ | engine/src/flutter | 三档 har + gen_snapshot 二进制工件 | 新增 shell/platform/ohos(826 文件) |
| 嵌入层 Embedder | 平台语言 | 各平台模板工程 | HAP 里的 entry 工程 | 整层重写(ArkTS + C++) |
注意一个反直觉的点:这张官方表格里没有鸿蒙那一格。Android 嵌入层用 Java + C++,iOS/macOS 用 Swift + ObjC,Windows/Linux 用 C++——鸿蒙是空的,社区分叉补的就是它。一句话记住这节:三层复用、一层重写,换平台只需要给嵌入层和引擎的平台目录补一份实现。
1.2 一帧画面的旅程:适配落在哪一步
Flutter 渲染一条 vsync 到像素上屏,走五步:
- build:调用
build()返回 Widget 子树(框架会按需展开,所以 DevTools 里的树比你写的深); - layout:深度优先遍历,约束自上而下传递、尺寸自下而上上报,布局复杂度 O(n);
- paint:生成绘制指令(LayerTree / DisplayList);
- composite:
RenderView.compositeFrame()创建画面,完成后交给dart:ui的Window.render()——这是 Dart 世界和 C++ 世界的交接点; - rasterize:引擎(Impeller / Skia)把场景栅格化成 GPU 指令、提交、送显。

上图下排标出了鸿蒙适配的落点:前四步是纯 Dart 逻辑,一行都不用改——这是 Flutter 跨平台的立身之本;从第⑤步栅格化往后全要重做:拿什么窗口画(XComponent)、用什么 GPU API(Vulkan)、字体从哪来(鸿蒙的 OH_Drawing)、事件从哪进(NAPI),这四件事在鸿蒙上都是新写的。
这里顺手记三条诊断经验,后文踩坑时会反复用到:
- 红屏、溢出条纹、布局慢 → UI 线程(build 太重或每帧重建太多);
- 掉帧、首帧慢 → 栅格线程(着色器与纹理准备);
- 编译零报错但所有文字图标全没了 → 断点在栅格化之前,是字体管理器/字体端口的问题(这个坑本系列第 10 篇专门讲)。
顺便解释一个常见困惑:为什么 DevTools 里的 Widget 树比你写的代码层级深?看这段源码就明白了:
// packages/flutter/src/widgets/container.dart(简化)
Widget buildContainer(...) {
Widget current = child;
// 颜色不是画在 Container 上,而是拆成一个独立的 ColoredBox 插进树里
if (color != null) {
current = ColoredBox(color: color, child: current);
}
// 同理:Image 展开成 RawImage,Text 展开成 RichText
return current;
}
「树更深」不是 bug,是组合式设计的必然结果。
1.3 为什么「可以」适配:稳定 ABI 与三个接缝
Flutter 又不是为鸿蒙设计的,凭什么能跑?答案在官方架构文档里的两句话:
- 「Flutter 的界面构建、布局、合成和绘制全都由 Flutter 自己完成,而不是转换为对应平台系统的原生组件」;
- 「Flutter 引擎本身是与平台无关的,它提供了一个稳定的 ABI(应用二进制接口),包含一个平台嵌入层,可以通过其方法设置并使用 Flutter」。
第一句是 Flutter 与 React Native 的分水岭:RN 是「我写 JS,你的系统控件来渲染」,每支持一个平台就得跟那个平台的控件体系较劲;Flutter 反过来——我自己画像素,我不需要你提供我依赖的控件,我只需要你给一块能画的地方。第二句的「稳定 ABI」是工程上的定心丸:引擎对外承诺的二进制接口不轻易变,嵌入层可以独立演进。
把这两句合起来,适配的可行性就落地成三个接缝——引擎和操作系统之间仅有的三处必须握手的接口:
| 接缝 | 职责 | Android | iOS | 鸿蒙 |
|---|---|---|---|---|
| ① 像素出口 | 创建 Flutter 可以写入的表面 | FlutterView(视图/纹理模式) | FlutterViewController + CALayer | XComponent → OHNativeWindow → VKSurface |
| ② 输入与生命周期 | 触摸、生命周期、窗口变化、事件循环 | Activity | UIViewController | UIAbility/FlutterAbility + NAPI 桥 |
| ③ 平台能力 | 跨语言调用 | MethodChannel + dart:ffi(Kotlin HashMap / Swift Dictionary) | 同左 | 同一套 channel;FFI 需要 Abi.ohosArm64 |
接缝③最有意思,因为它基本不需要为鸿蒙重写:MethodChannel 的数据由 Dart 序列化成标准格式再反序列化到平台侧,鸿蒙只需在 ArkTS 侧实现同一套接收端。但这里埋着一个大坑——FFI 这条路依赖 Dart 的 Abi 枚举认得目标平台,官方 Dart SDK 里没有 Abi.ohosArm,所以鸿蒙上 FFI 相关能力必须靠定制 Dart SDK(1.4 节的 L1 层)。
官方还给自定义嵌入层留了一扇门:文档明确「开发者可以创建自定义的嵌入层」,并给了 VNC 帧缓冲和树莓派两个例子。所以鸿蒙写一套嵌入层不是野路子,是官方设计意图之内的事。
1.4 适配到底做了多少事:自底向上七层清单
「为什么可以适配」讲完了,这一节回答「适配到底做了多少事」。社区的工作可以拆成自底向上的七层,层与层之间有依赖顺序——上面任何一层都要求下面已经就位:

上图是完整的七层工作量与验收判据图。压缩成一张表(文件数来自 3.44.9→3.47.4 同步批次实录):
| 层 | 做了什么 | 验收判据 |
|---|---|---|
| L1 Dart SDK/运行时 | 补 Abi.ohosArm/ohosArm64/ohosX64、Platform.isOhos,重建 patched_sdk 与 dart-sdk | Dart 里能打印 Abi.ohosArm64;flutter analyze 0 error |
| L2 引擎平台目录 | 新增 shell/platform/ohos(C++):窗口、输入、生命周期、插件注册、字体端口 | 三档引擎 ninja 0 FAILED;引擎单测真机 1723/1723 |
| L3 渲染后端 | Impeller 走 Vulkan:建面、外接纹理、GPU 同步、防花屏 | 真机有画面、不花屏、首帧时延达标 |
| L4 宿主与桥接 | ArkTS 侧 FlutterAbility / XComponent + NAPI 桥 | flutter run 热重载可用;返回键与生命周期正确 |
| L5 框架层 | TargetPlatform.ohos、默认字体与滚动/返回手势 | 字体图标可见;交互符合鸿蒙习惯 |
| L6 工具链 | flutter_tools/lib/src/ohos/ 13 个源文件 + cache.dart 工件接线 | flutter doctor -v 全绿;devices 能列出鸿蒙设备 |
| L7 发布与分发 | 版本锁 + 工件发布 + Release 附件 | 全新机器装 tag → build hap → 零手工步骤 |
七层清单里有两个对消费侧很有用的信号:
- L6 工具链:
flutter doctor -v能不能全绿、flutter devices能不能列出鸿蒙设备,是你判断「SDK 装对了没有」的最快信号(本篇 5.4 节的自检会用到); - L7 发布与分发:L1/L2 的产物是二进制工件,有特别阴的特征——改了源码没重发、或重发了没换 tag,用户侧完全无感,静默用旧货。这也是后文版本核验要盯到
flutter.version.json粒度的原因。
本篇只站在消费侧视角:怎么拿到、装上、验证这七层工作已经打包好的产物。
七层工作本身的生产侧细节(怎么改、怎么验证、怎么发布),本系列第 4-11 篇逐层展开。
二、鸿蒙版 Flutter:仓库与两种发布形态
2.1 它不是官方 SDK
先明确一个概念:鸿蒙版 Flutter(下文简称 ohos Flutter)是**分叉(fork)+ 补丁(patch)**的产物。社区团队拿到上游 Flutter 仓库的源码,在其上叠加一套面向 OpenHarmony 的适配补丁——就是 1.4 节那七层。
这意味着三件事:
- 版本号里会带
-ohos标记,与官方版本号体系平行但不对等; - 它的更新节奏跟随上游发版,但不是自动同步,每次同步都是一次完整的大工程(涉及数千文件重打与冲突裁决);
- 安装来源是社区仓库,不是
flutter.dev的官方发行版。
2.2 仓库与发布形态
需要关注的维护线只有一条:atomgit.com/oh-flutter/flutter_flutter。它最早 fork 自社区的另一支鸿蒙分叉,之后持续同步上游 github.com/flutter/flutter 并做鸿蒙适配,因此同步到的上游版本更新。两支的用法完全一致——同样的目录结构、同样的版本命名、同样的安装命令,本系列后续只以 oh-flutter 这条线为准。
真正决定你怎么安装的,是发布形态(同一个仓库里两种形态都有):
| 形态 | 例子 | 怎么查 | 安装引用 |
|---|---|---|---|
| git tag(当前发布线) | 3.47.8-ohos-1.0.0、3.47.4-ohos-1.0.4 | git ls-remote --tags | fvm install <别名>/<tag> |
| 分支名(历史线) | oh-3.44.9-dev、oh-3.35.7-release | git ls-remote --heads | fvm install <别名>/<分支> |
仓库统一托管在 AtomGit,直接
git clone https://atomgit.com/oh-flutter/flutter_flutter.git即可。
这里先把本篇最重要的结论摆出来,后面几章都是在证明它:tag 版本不需要绕开 fvm。fvm 的 fork 别名接受任意 git 引用(tag、分支、commit 都可以),把 tag 名当版本参数传进去就能装,装完还会自动跑首次初始化。第五章是这条路径的完整实测(clone 76.8 秒 + 自动下载定制 Dart SDK)。
2.3 与上游的关系:同步 + 适配
每个 ohos 版本都基于某个上游 Flutter 版本打出,它与上游的关系可以拆成两半:
- 同步:框架代码、Dart SDK、DevTools 跟随上游演进,
flutter.version.json里的frameworkRevision是 fork 自己的提交; - 适配:fork 额外维护两套定制产物——
- 定制引擎:
bin/internal/engine.ohos.version指向 ohos 引擎,与上游engine.version不是同一个值(这是故意的,不是 bug); - 定制 Dart SDK:
bin/internal/dart-sdk-url.ohos指定下载地址,因为官方 dart-sdk 不支持鸿蒙 ABI(1.3 节接缝③埋的坑)。
- 定制引擎:
还有一个实用入口:仓库根目录的 CHANGELOG_OHOS.md 是 ohos 专属变更日志(不是上游的 CHANGELOG.md),升级前值得通读——ohos 侧修了什么(PlatformView 坐标、GPU 资源回收、输入法回调……)只有这里写得最权威。
三、版本命名规则:看懂 -ohos- 补丁号
3.1 分支名:oh-<上游版本>-release
例如 oh-3.44.9-dev,这是仓库里的分支名(历史线以分支发布,当前线以 tag 发布,见 2.2 节)。这里有一个最容易踩的认知坑:
分支名不等于实际版本号。
oh-3.44.9-dev装出来,flutter --version显示的是3.44.9+ohos-0.0.1-canary1——分支 HEAD 已经比 3.44.9 多打了几轮补丁。
所以任何「以版本为准」的判断,都不要看分支名,要看装好之后的元数据(3.3 节)。
3.2 tag 名:<上游版本>-ohos-<补丁版本>
oh-flutter 仓库以 tag 发布,例如 3.47.5-ohos-1.0.0:
3.47.5= 对应上游 Flutter 3.47.5;1.0.0= ohos 分叉自己的迭代补丁号,同一补丁线还有1.0.1、1.0.2……
命名结构图解(含「分支名 ≠ 实际版本」对照):

上图展示了 3.47.5-ohos-1.0.0 的版本号解剖,以及分支名与实际版本的对照关系;右半部分是定制引擎的版本锁体系(生产侧内容,本篇只需知道「引擎版本与上游不同是正常的」)。
3.3 最终权威:flutter.version.json
每个已安装 SDK 的 bin/cache/flutter.version.json 里有最终生效的版本元数据,这是判断装没装对的唯一权威来源:
{
"frameworkVersion": "3.47.5-ohos-1.0.0",
"channel": "[user-branch]",
"repositoryUrl": "https://atomgit.com/oh-flutter/flutter_flutter.git",
"frameworkRevision": "39481acce8b9e6bb902714e6705c8baf75662d49",
"dartSdkVersion": "3.13.4",
"devToolsVersion": "2.60.0"
}
各字段含义与判断方法:
| 字段 | 含义 | 怎么用 |
|---|---|---|
frameworkVersion | 最终版本号(X.Y.Z-ohos-N.M.K) | 目标版本以此为准 |
repositoryUrl | 实际来源仓库 | 一眼看出这套 SDK 是从哪个仓库、哪个域名装的(旧域名装的会留痕,见 CP3) |
frameworkRevision | fork 框架提交 | 判断是否为最新补丁 |
engineRevision | fork 使用的引擎 | 与上游 engine 不同属正常 |
dartSdkVersion | Dart SDK 版本 | 与上游大版本一一对应(3.44→3.13,3.47→3.13) |
devToolsVersion | DevTools 版本 | 同步成功的旁证 |
四、安装前准备
4.1 前置条件
- 安装 fvm 4.x(本机为 4.3.1,Homebrew 安装,
fvm --version可验证)——fork 别名是这条安装路径的前提,fvm fork --help能看到add/list/remove三个子命令; - 了解 fvm 的 SDK 缓存目录:
~/fvm/versions(fvm list会显示 Cache directory); - 预留磁盘与时间:分叉仓库体量大,且首次初始化拿到的 Dart SDK 是鸿蒙定制版——以 macOS(arm64)为例,
dart-sdk-darwin-arm64-ohos.zip是 225,700,875 B ≈ 215 MiB,Windows x64 对应包是 206.6 MiB,再加 HAP 构建专用运行时dart-sdk-ohos.zip(8.5 MiB)与引擎 har / patched_sdk。实测两套体积:fvm 直装 tag 落地 3.1 GB(.git占 2.0 GB,完整克隆),手动浅克隆 bootstrap 落地 1.4 GB(.git只有 141 MB);时间都在两分钟内(5.2 节实测 1 分 49 秒)。全量工件表见第 9 篇。
fvm 在这里的角色是「多版本 SDK 管理器」:不同项目绑定不同版本的 Flutter(含 fork),互不污染。如果你不需要多版本管理,直接手动 clone 也可以,但 fvm 能让 flutter 命令自动解析到项目绑定的版本,体验更好。
4.2 国内镜像配置
国内网络下,务必先切镜像,否则引擎产物会从海外 OBS 慢速下载,第一步就可能卡死:
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
export PUB_HOSTED_URL=https://pub.flutter-io.cn
提示:这两个环境变量建议写进
~/.zshrc或~/.bashrc长期生效。
其中PUB_HOSTED_URL指向 pub.flutter-io.cn 国内镜像,后续flutter pub get也依赖它。
4.3 先查仓库里到底有哪些 tag / 分支
fvm 不会帮你列 fork 的引用(fvm releases 只给上游发布列表),装之前先用 git ls-remote 看仓库里有什么:
git ls-remote --tags https://atomgit.com/oh-flutter/flutter_flutter \
| sed 's|.*refs/tags/||' | grep -v '\^{}' | sort -V | tail -11
实测输出(2026-10-28 记录,节选尾部):
3.41.10-ohos-1.0.0
3.41.10-ohos-1.0.1
3.47.4-ohos-1.0.0
3.47.4-ohos-1.0.1
3.47.4-ohos-1.0.2
3.47.4-ohos-1.0.3
3.47.4-ohos-1.0.4
3.47.5-ohos-1.0.0
3.47.7-ohos-1.0.0
3.47.7-ohos-1.0.1
3.47.8-ohos-1.0.0
历史分支线仍在同一个仓库里,需要对照时查 heads:
git ls-remote --heads https://atomgit.com/oh-flutter/flutter_flutter \
| sed 's|.*refs/heads/||' | grep '^oh-' | tail -8
oh-3.35.7-release
oh-3.41.9-dev
oh-3.41.9-release
oh-3.44.9-dev
oh-3.47-dev
oh-3.47.4-dev
计数口径提醒:
git ls-remote --tags会把 peeled 引用(xxx^{})一起打出来,数 tag 之前先grep -v '\^{}'。实测这个仓库的--tags输出 109 行、--heads输出 55 行,去掉 peeled 后真正的 tag 是 83 个。
命名规律统一:<上游Flutter版本>-ohos-<分叉补丁号>,canary / beta 后缀表示预发布,生产环境选无后缀的正式版 tag。83 个 tag 里 60 个严格符合这条规律,剩下 23 个是历史形态,四类值得知道:
oh-3.47.4-rc1:候选期产物,唯一的oh-前缀 tag,只挂了 1 个定制 Dart SDK 附件;- 裸
3.47.4:不带-ohos-段,别当成 OH 发布版; 3.44.9+ohos-0.0.1-canary1:用+而非-接 build metadata,正是 3.1 节那个「分支名 ≠ 版本号」的产物形态;github.com/flutter/flutter/3.27.4这类 3 个:同步锚点 tag,标记「同步到上游哪个提交」,不是发布版。
另外 tag 列表里没有 3.47.6-ohos-*——上游 3.47.6 → 3.47.7 全是 iOS 平台改动,与 OHOS 无关,所以 3.47.6 没有独立发布,改动直接并入 3.47.7-ohos-1.0.0 批次(这条判断在 bin/internal/dart-sdk-url.ohos 的注释里有原始记录)。
五、路径 A 实操:用 fvm fork 直装 tag 版本(推荐)
适用场景:tag 和分支都能用这条路径装,这也是本系列推荐的第一条路。两条安装路径的整体决策流程:

上图左绿是本篇的推荐路径(fvm fork 直装,引用写 tag 或分支都行),右蓝是兜底的手动 bootstrap(第 2 篇);中间橙色框就是本章要先破除的误区。装完统一做 5.4 节的三步自检。
5.1 注册 fork 别名
fvm fork add ohos https://atomgit.com/oh-flutter/flutter_flutter.git
fvm fork list # 确认别名指向哪个仓库
ohos 是给这个仓库起的别名(alias),叫什么随意,它只是本机缓存目录的前缀 ~/fvm/versions/<别名>/;之后安装统一用 <别名>/<版本引用>,引用可以是 tag、分支,也可以是 commit。配套三个子命令:fvm fork add / fvm fork list / fvm fork remove。
小坑:fvm 只把「别名 → 仓库 URL」记在本地,不会帮你列这个仓库有哪些 tag 或分支,引用名得靠 4.3 节的
git ls-remote自己查;而且别名指错仓库时注册不会报错,要等到安装那一步才失败——所以装之前先fvm fork list核对一遍。
5.2 安装 tag 版本(完整实测)
fvm install ohos/3.47.8-ohos-1.0.0
3.47.8-ohos-1.0.0 就是 4.3 节查到的 tag 名,直接当版本参数传给 fvm。真实输出(fvm 4.3.1,2026-10-28 记录;这台机器的别名起名叫 nutpi,换成你自己的别名即可,其余逐字一致):
Installing Flutter SDK: SDK Version : nutpi/3.47.8-ohos-1.0.0...Using forked repository URL: https://atomgit.com/oh-flutter/flutter_flutter.git
✓ Flutter SDK: SDK Version : nutpi/3.47.8-ohos-1.0.0 installed! (76.8s)
Setting up Flutter SDK: 3.47.8-ohos-1.0.0
Downloading Darwin arm64 Dart SDK from Flutter engine cf636b1dfb818dd6a3ff16e390e93b1a036969c8...
OHOS: using customized Dart SDK (dart-sdk-darwin-arm64.zip) from https://atomgit.com/oh-flutter/flutter_flutter/releases/download/3.47.8-ohos-1.0.0/dart-sdk-darwin-arm64-ohos.zip
OHOS: downloading customized Dart SDK runtime (dart-sdk-ohos.zip) from https://atomgit.com/oh-flutter/flutter_flutter/releases/download/3.47.8-ohos-1.0.0/dart-sdk-ohos.zip
Building flutter tool...
Resolving dependencies...
Got dependencies.
Flutter 3.47.8-ohos-1.0.0 • channel [user-branch] • https://atomgit.com/oh-flutter/flutter_flutter.git
Framework • revision 9d2002f780 (4 days ago) • 2026-10-25 07:12:07 +0800
Engine • hash dfd2e6cb7d319db05e3bf1503f3e2ac60f6288a2 (revision cf636b1dfb) (5 days ago) • 2026-10-23 02:13:38.000Z
Tools • Dart 3.13.4 • DevTools 2.60.0
四条值得注意的信息:
- clone 只花 76.8 秒。
fvm install默认带--setup,装完接着跑首次初始化:下载定制 Dart SDK(215 MiB)与 HAP 构建运行时(8.5 MiB)、编译 flutter tool,端到端 1 分 49 秒。不想让它自动初始化就加--no-setup; - 日志里那两行
OHOS: ... from .../releases/download/3.47.8-ohos-1.0.0/...就是第 9 篇讲的覆盖行机制在起作用——fork 把 Dart SDK 的下载地址改指到了自己的 Release 附件,官方源上没有这两个包; - 落地目录是
~/fvm/versions/<别名>/<tag名>(本机~/fvm/versions/nutpi/3.47.8-ohos-1.0.0),目录名就是 tag 本身,不需要自己起名; - 这套副本的 HEAD 停在 tag 上(detached),
.git是完整克隆(实测 3.1 GB,其中.git占 2.0 GB)。别去git pull,要升级就装新 tag;想省磁盘就走近 2 篇的浅克隆。
5.2b 分支形态同理(历史线对照)
同一套命令,把引用换成分支名即可:
fvm install ohos/oh-3.35.7-release
装完 flutter --version 报出来的是 3.35.8-ohos-1.0.4——分支名 ≠ 实际版本号(3.1 节),一切以 flutter.version.json 为准。同理 oh-3.44.9-dev 装出来是 3.44.9+ohos-0.0.1-canary1。
5.3 在项目里切换
cd <你的项目目录>
fvm use ohos/3.47.8-ohos-1.0.0
这会在项目根目录生成/更新 .fvmrc,并创建 .fvm/ 软链:
{
"flutter": "ohos/3.47.8-ohos-1.0.0"
}
两个配套动作:
- 把
.fvm/加进项目的.gitignore(软链指向本机绝对路径,提交进仓库会坑到队友); - 项目内所有
flutter命令此后都走 fvm 解析:fvm flutter pub get、fvm flutter run -d <设备>。
5.4 装完三步自检
装完不要直接开跑,按顺序做三层核验(层层递进,越往后越权威):
- fvm 层面:确认缓存目录结构与项目绑定关系;
- flutter 层面:确认最终生效版本符合预期;
- 元数据层面:确认
flutter.version.json的每个字段都对得上。
# ① fvm 层面
fvm list
# ② flutter 层面
fvm flutter --version
# ③ 元数据层面(最权威)
cat ~/fvm/versions/<别名>/<版本名>/bin/cache/flutter.version.json
第三层看到的 frameworkVersion / repositoryUrl / dartSdkVersion 与 3.3 节表格对照,全部符合预期,才算「装对了」。如果涉及真机运行,再加一层工具链自检(对应 1.4 节 L6 的验收判据):
fvm flutter doctor -v # 鸿蒙工具链是否就绪
fvm flutter devices # 能否列出鸿蒙设备/模拟器
六、什么时候仍需手动 bootstrap
fvm 直装 tag 已经跑通,路径 B 就不是「tag 的唯一解」了。它剩下的价值是可控与省磁盘,但在讲场景之前,得先把「fvm 装 tag 会失败」这个流传很广的说法纠正过来。
6.1 先看清失败的真实原因:不是不认 tag,是去错了仓库
最常见的失败长这样:
fvm install 3.47.8-ohos-1.0.0 # ← 少了别名前缀
加 --verbose 跑一次,日志会直接交代它在干什么(真实记录):
Skipping git reference validation for version: 3.47.8-ohos-1.0.0
Git cache not found. Creating heads/tags cache...
Creating local git cache...
也就是说:fvm 把这个字符串当成一个git 引用去查,而它用的默认仓库是 https://github.com/flutter/flutter.git——建本地 bare 缓存时写进 config 的 remote url 就是这条。上游仓库里当然没有 3.47.8-ohos-1.0.0,于是卡住或失败。结论:fvm 认 tag,不认的是「没有 fork 别名时的默认仓库」。
| 成因 | 判据 | 处置 |
|---|---|---|
| 忘了写别名 | 命令里没有 <别名>/ 前缀 | fvm install <别名>/<tag>(5.2 节) |
| 别名指向不对 | fvm fork list 打出的 URL 不是你要的仓库 | fvm fork remove <别名> 再重新 add |
| fvm 太旧没有 fork 能力 | fvm fork --help 报错 | 升到 4.x(本机 4.3.1 实测可用) |
6.2 仍然该走手动 bootstrap 的四个场景
- 机器上不想装 fvm:CI 镜像、临时排障机、给别人复现问题;
- 要省磁盘:浅克隆只留 1 个提交,实测落地 1.4 GB,对比 fvm 全量克隆的 3.1 GB(4.1 节);
- 要精确控制落地位置与目录名:例如把 SDK 固定放到约定路径给脚本用;
- 要看清 fvm 替你做了什么:首次初始化、flutter_tools 的 SSH 依赖 URL、镜像变量这几个坑,手动走一遍才知道边界在哪——这正是第 2 篇存在的全部理由。
口径:遇到「版本墙」(第 8 章详述),解法永远是升分叉版本;升到哪个版本看 4.3 节的 tag 墙,装法优先 fvm 直装,上面四种场景才走手动。
七、版本对照表:已核实的五套 SDK
7.1 本机实装 SDK 一览
以下元数据全部取自本机实际安装 SDK 的 bin/cache/flutter.version.json(2026-10-28 记录):
ls ~/fvm/versions/*/
# nutpi/: 3.47.7-ohos-1.0.1 3.47.8-ohos-1.0.0
# ohos/: oh-3.32.0-release oh-3.35.7-release oh-3.47.5-release
fvm 目录(别名/版本) | frameworkVersion | 来源仓库 | frameworkRevision | 提交日期 | engineRevision | Dart | DevTools | 装法 |
|---|---|---|---|---|---|---|---|---|
nutpi/3.47.8-ohos-1.0.0 | 3.47.8-ohos-1.0.0 | atomgit/oh-flutter | 9d2002f780 | 2026-10-25 | cf636b1dfb | 3.13.4 | 2.60.0 | fvm 装 tag |
nutpi/3.47.7-ohos-1.0.1 | 3.47.7-ohos-1.0.1 | atomgit/oh-flutter | 62d280c5bc | 2026-10-21 | deb287481e | 3.13.4 | 2.60.0 | fvm 装 tag |
ohos/oh-3.47.5-release | 3.47.5-ohos-1.0.0 | gitcode/oh-flutter | 39481acce8 | 2026-09-23 | af7e796e16 | 3.13.4 | 2.60.0 | 手动浅克隆 |
ohos/oh-3.35.7-release | 3.35.8-ohos-1.0.4 | atomgit/CPF-Flutter | 04d2008b35 | 2026-09-24 | 035316565a | 3.9.2 | 2.48.0 | fvm 装分支 |
ohos/oh-3.32.0-release | 3.32.4-ohos-0.0.1 | atomgit/CPF-Flutter | dae30486e6 | 2026-05-21 | 8cd19e509d | 3.8.1 | 2.45.1 | fvm 装分支 |
这张表里有五条可以直接抄走的判据:
- 目录名会出卖你的装法:fvm 装 tag 时目录名就是 tag 本身(
nutpi/3.47.8-ohos-1.0.0),fvm 装分支时目录名是分支名,手动 bootstrap 时目录名是你自己起的(第三行oh-3.47.5-release); - 分支名 ≠ 版本号:
oh-3.35.7-release实际是3.35.8-ohos-1.0.4,oh-3.47.5-release实际是3.47.5-ohos-1.0.0——一切以frameworkVersion为准(3.1 节); - 旧域名会在元数据里留痕:第三行的
repositoryUrl是atomgit.com/oh-flutter/...,那是仓库迁移前的地址。现在统一用 AtomGit(CP3),但已装好的 SDK 不会自动改写这个字段,看它就能判断这套 SDK 是什么时候、从哪个域名装的; - Dart 版本能反推上游线:3.32→Dart 3.8.1、3.35→3.9.2、3.47→3.13.4,跨线升级必然伴随 Dart 大版本变化,依赖要重解(8.3 节);
- 多套 SDK 共存互不干扰:同一台机器上五种装法、三个来源都在,靠各项目
.fvmrc里那一行决定用哪个。
最后两行是更早的分支历史线(3.32 / 3.35),保留在这里只作版本对照——用法与 oh-flutter 完全一致,本系列后续一律以 oh-flutter 的 tag 线为准。
7.2 上游 ↔ 分叉版本换算规则
- 已知上游官方大版本
X.Y:分叉分支名形如oh-X.Y.Z-release,分叉 tag 形如X.Y.Z-ohos-N.M.K; - 想确认某个分叉基于哪个上游:看
dartSdkVersion——Dart 版本与上游 Flutter 版本一一对应(3.44→3.13、3.47→3.13); - 引擎版本不要与上游对比:
engineRevision是 ohos 定制引擎,与上游 flutter/engine 的 revision 没有可比性,对不上是正常现象。
上游参照(本机实测的官方对应关系):
| 上游 Flutter | Dart | DevTools |
|---|---|---|
| 3.47.x | 3.13.4 | 2.60.0 |
7.3 版本选择建议(基于历史结论)
| 需求 | 选哪个 | 理由 |
|---|---|---|
| 稳定开发、生态验证最充分 | oh-flutter 3.47.8-ohos-1.0.0 | Dart 3.13.4,当前发布线,实测 pub 可解析 |
| 需要旧线行为对照 | oh-3.35.7-release(实际 3.35.8-ohos-1.0.4) | 分支形态的历史线,同一套 fvm 命令 |
| 回退到上一版 | 3.47.7-ohos-1.0.1 | 3.47 线上一发布,fvm 装法完全相同 |
选型的核心原则只有一条:先看第三方依赖的最低 Flutter 约束,再在满足约束的分叉版本里挑最新补丁号。约束不满足时,任何配置技巧都绕不过去——只能升版本。
八、版本墙:第三方包逼你升级
8.1 真实报错
版本墙是消费侧最常见的「硬阻断」。真实记录如下(flutter pub get 失败):
The current Flutter SDK version is 3.44.9+ohos-0.0.1-canary1.
Because <package> depends on <dep> which requires SDK version >= 3.41.0,
version solving failed.
...suggestion to make the pubspec resolve:
* Try using the Flutter SDK version: 3.47.6.
8.2 读懂报错:别照着建议版本号装
这个报错里有一个极具误导性的细节:
建议的
3.47.6是上游官方版本号,不是 ohos 分叉的版本号——本机根本装不了这个版本。
正确动作是把 ohos SDK 升到满足约束的分叉版本(本例为3.47.8-ohos-1.0.0,框架功能对应上游 3.47.x)。
处理路径按顺序执行:
- 确认目标分叉版本存在(4.3 节查分支/tag);
- 装好新 SDK:
fvm install <别名>/<tag>(5.2 节);只有在 6.2 节那四种场景下才走手动 bootstrap; - 项目内
fvm use切换到新版本; - 重新
fvm flutter pub get,确认解析通过。
# 升级后一键核验:版本横幅 + 依赖解析
fvm flutter --version && fvm flutter pub get
8.3 大版本升级后的三个注意点
3.44 → 3.47 跨了一个大版本,Dart 从 3.13.x 跟进到 3.13.4,升级不是无感的:
- 依赖要重解:切换后必须重新
flutter pub get,旧的.dart_tool解析结果作废;第三方包/插件可能需要重新适配,或自身存在 API 变更; - 引擎不要对比上游:引擎是 ohos 定制引擎(
engine.ohos.version),拿上游engine.version去对是错误姿势,两者故意不同; - 升级前先读
CHANGELOG_OHOS.md:它列出了 ohos 侧每个补丁修了什么。下面是一段真实摘录(3.44.9+ohos-1.0.5,2026-09-24):
### Added
- feat(flex_overflow): dynamic DPI overflow strategy,修复动态DPI下PlatformView点击事件坐标分布异常
- feat: parseOhosVersion supports +ohos build metadata format
- feat(ohos): 完善GPU资源回收全流程日志埋点
### Changed
- change(Template): OHOS模板targetSdkVersion升级至26.0.0并统一compatibleSdkVersion至5.0.5(17)(自旧版本线延续)
### Fixed
- 修复StandardMessageCodec.writeValueInternal绕过子类覆写导致序列化失败(自旧版本线延续)
- fix(safearea): correct safe area padding for edgeToEdge and freeform window exit
- fix(DEPS_ohos): update skia_revision for font alias fix
升级决策完全可以基于它做:需要哪个修复/能力 → 找到含该条目的版本 → 用对应的 tag/分支装。
九、常见问题 FAQ
9.1 高频问题速查
把本篇涉及的所有坑汇总成一张速查表(后文篇目会展开更细的坑体系):
| # | 现象 | 原因 | 解法 |
|---|---|---|---|
| CP4 | fvm install 卡死在下载 | 未切国内镜像,走海外 OBS 慢速通道 | 先 export 两个镜像变量(4.2 节) |
| CP9 | 装了 oh-3.44.9-dev 却显示 3.44.9+ohos-0.0.1-canary1 | 分支 HEAD 已含后续补丁 | 正常现象,以 flutter.version.json 为准(3.1 节) |
| CP5 | fvm install 3.47.8-ohos-1.0.0 卡住/失败 | 没带 fork 别名,fvm 拿默认仓库(官方 flutter/flutter)去查这个引用 | 写成 fvm install <别名>/<tag>,先 fvm fork list 核对指向(6.1 节) |
| CP11 | 队友 clone 项目后 flutter 命令失效 | .fvm/ 软链被提交进仓库,指向你的绝对路径 | .fvm/ 加入 .gitignore,队友自行 fvm use(5.3 节) |
| CP8 | pub get 报 requires SDK version >= 3.41.0 | 版本墙:分叉版本低于依赖约束 | 升分叉版本,别照报错里的上游版本号装(第八章) |
| CP12 | 用上游 engine.version 对比 ohos 引擎「对不上」 | ohos 定制引擎与上游故意不同 | 看 engine.ohos.version,不与上游对比(7.2 节) |
| CP3 | 旧文章/脚本里的仓库域名与实际不符 | 仓库已统一迁移到 AtomGit | 一律改用 atomgit.com 地址(2.2 节) |
9.2 现在应该装哪个版本?
直接装 oh-flutter 的 tag 3.47.8-ohos-1.0.0,一条命令:fvm install <别名>/3.47.8-ohos-1.0.0(5.2 节实测)。只有维护旧项目、需要复现历史分支线行为时,才把引用换成分支名(5.2b 节)。DevEco Studio 配套 26.0.0 Release,SDK/API 为 26。
9.3 fvm install <别名>/<tag> 还是失败,怎么排?
按 6.1 节的三条成因过一遍:别名前缀有没有写、fvm fork list 里别名指向的仓库对不对、fvm 是不是旧到没有 fvm fork 子命令。三条都排掉了,再加 --verbose 看它到底在跟哪个仓库要哪个引用;确认是环境限制(磁盘、CI、离线)才转手动 bootstrap(第 2 篇)。
9.4 环境变量该按哪个版本配置?
以 DevEco Studio 26.0.0 Release 的安装路径为准:DEVECO_SDK_HOME 指向 .../Contents/sdk,JAVA_HOME 指向 .../Contents/jbr/Contents/Home,并把 ohpm、node、hvigor、hdc 加入 PATH;完整步骤见文首环境搭建指导。
十、系列导航
本文是「鸿蒙Flutter框架 0day适配实战」系列的第 1 篇。全系列 10 篇,分消费侧(4 篇)与生产侧(6 篇)两部分,背景内容已并入本篇开头,不再单独成篇:
| # | 篇目 | 侧 | 一句话主题 |
|---|---|---|---|
| 01 | 背景、分叉仓库、版本命名与 fvm fork 安装(本篇) | 消费 | 三层架构、三个接缝、七层工作量、fvm 直装 tag、版本墙 |
| 02 | tag 版本的手动安装与三层核验 | 消费 | 浅克隆 bootstrap、首次初始化、SSH 修复、异常分诊 |
| 03 | 鸿蒙模拟器/真机跑 Flutter + 消费侧踩坑集 | 消费 | 工具链三件套、HAP 构建/安装/运行、占位签名、截图取证、CP1-CP14 |
| 04 | flutter build hap 自动签名 | 消费 | P12/CSR、AGC 证书与 Profile、纯 Dart AES-GCM、C0-C10 复用 |
| 05 | 上游同步总览、BC 全景与端到端 SOP | 生产 | 批次解剖、五阶段验证门、12 项适配表、端到端 SOP 与 P1-P29 索引 |
| 06 | Phase 1+2:基线建立与 Framework 适配 | 生产 | 代理 HTTP/1.1 修障、421 文件重打、Dart SDK 源码构建 |
| 07 | Phase 3 Engine:三方重放与冲突裁决 | 生产 | 826 文件、15 真冲突两分法、契约对齐 16 项 |
| 08 | 引擎构建链攻防 | 生产 | 依赖树、工具链版本、链接与测试面 27 坑 |
| 09 | 构建发布与产物分发 | 生产 | 版本锁、11 个工件(Dart SDK 双宿主)、11 条覆盖键、换新 tag 铁律 |
| 10 | 验证与真机验收 | 生产 | 三档引擎、设备侧单测、字体图标静默故障 |
配套仓库与文档:
- 分叉仓库(3.47 线):atomgit.com/oh-flutter/flutter_flutter
- 自研组件库 harmony_ui(鸿蒙设计系统 for Flutter):atomgit.com/oh-flutter/harmony_ui
总结
本篇作为系列开篇,先用一章把背景讲透:Flutter 三层架构里只有嵌入层和操作系统直接相关,官方稳定 ABI 把平台差异压缩进「三个接缝」,社区适配做了 L1-L7 七层工作、每层都有明确验收判据;之后进入消费侧主线——一条 oh-flutter 维护线、两种发布形态(tag 与历史分支),分支名 ≠ 实际版本号,一切以 flutter.version.json 为最终权威;安装首选 fvm fork 别名 + tag,一条命令 1 分 49 秒装完并自动初始化,手动 bootstrap 退居兜底;遇到版本墙时,先读懂报错里「上游版本号」的误导,再选对分叉版本升级。
下一篇(第 2 篇)讲兜底路径:在没有 fvm、要省磁盘、或想看清 fvm 替你干了什么的时候,手动 bootstrap 一个 tag 版本(实例 3.47.5-ohos-1.0.0,当前最新为 3.47.8-ohos-1.0.0)的完整五步、三层核验与异常分诊。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- oh-flutter 分叉仓库(当前 3.47 线,tag 3.47.8-ohos-1.0.0):atomgit.com/oh-flutter/flutter_flutter
- Flutter OH 环境搭建指导:https://atomgit.com/oh-flutter/flutter_samples/blob/master/ohos/docs/03_environment/OpenHarmony-flutter%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E6%8C%87%E5%AF%BC.md
- oh-flutter 分叉仓库(3.41+/3.47 线):atomgit.com/oh-flutter/flutter_flutter
- fvm 多版本管理器:github.com/leoafarias/fvm
- Flutter 官方架构文档:docs.flutter.dev 架构概览
- Flutter 官方文档:docs.flutter.dev
- Dart 官方文档:dart.dev
- pub 国内镜像:pub.flutter-io.cn
- Flutter 国内镜像配置说明:docs.flutter.cn(镜像与代理)
- AtomGit 平台(分叉仓库新家):atomgit.com
- 开源鸿蒙跨平台社区:openharmonycrossplatform.csdn.net
环境与版本
本文的示例与截图基于以下环境组合(2026-10 实测):
| 组件 | 版本 | 说明 |
|---|---|---|
| 上游 Flutter SDK | 3.47.8 | github.com/flutter/flutter |
| Flutter SDK(OH 适配版) | 3.47.8-ohos-1.0.0 | oh-flutter/flutter_flutter,oh-3.47-dev 分支 |
| DevEco Studio | 26.0.0 Release | 提供 hvigor / ohpm / hdc / JBR 等工具链 |
| OpenHarmony SDK / API | API 26(26.0.0) | 模拟器与 SDK 均为 API 26 |
| 运行设备 | OpenHarmony 模拟器 | API 26,1280×2832 |
环境搭建(分叉获取、DevEco Studio 与 SDK 配置、模拟器创建)请按官方指导操作:OpenHarmony-flutter 环境搭建指导。
本篇的安装命令全部在 fvm 4.3.1(Homebrew,macOS arm64)上实测;5.2b 的分支示例取
oh-3.35.7-release(实际版本3.35.8-ohos-1.0.4),只为讲清「分支名 ≠ 实际版本号」。日常安装直接用fvm install <别名>/3.47.8-ohos-1.0.0(5.2 节实测端到端 1 分 49 秒);第 2 篇的手动 bootstrap 是兜底路径,不是 tag 的唯一装法。
更多推荐


所有评论(0)