鸿蒙Flutter框架 0day适配实战:05 上游同步总览:批次解剖、Breaking Changes 全景与端到端同步 SOP
前言
版本口径(2026-10):当前正式发布版为 Flutter OH 3.47.8-ohos-1.0.0(atomgit.com/oh-flutter/flutter_flutter,
oh-3.47-dev线),配套 DevEco Studio 26.0.0 Release 与 OpenHarmony SDK / API 26。本篇记录的是 2026-09 的 3.44.9 → 3.47.4 历史同步批次,为保留批次现场而保留当时的坐标与数字;方法论与验证门对 3.47.8 同样适用。环境搭建见Flutter OH 环境搭建指导。
消费侧四篇到第 4 篇闭环:用别人的分叉 SDK,并把签名这一步也自动化。从本篇开始切换视角,进入生产侧(fork 维护者)——上游 Flutter 发了新版,如何把鸿蒙分叉同步上去、适配掉差异、构建发布出新的 SDK 工件。
本篇是整个生产侧六篇的总图:以 2026-09 的「3.44.9 → 3.47.4 上游同步批次」为标本,解剖一次完整同步批次的全部关键决策——为什么要同步、版本基线怎么定、2263 个适配文件由什么构成、3.47 的 Breaking Changes 有哪些、五阶段方案怎么切、风险在哪。后面的第 6-10 篇就是这张总图上逐个 Phase 的放大,本篇第七章则把整套打法压成下一批次可直接执行的 SOP。
材料口径:本篇所有数字与结论来自 2026-09-12 ~ 09-15 批次的实操留档,
路径已归一化为$ROOT(旧工作机路径,照做时替换成自己的)。
一、为什么同步:批次的背景与目标
1.1 版本墙与版本差距
消费侧第 1、3 篇反复出现过版本墙:第三方包声明最低 Flutter ≥ 3.41,而分叉落后上游多个版本时,生态包集体不可用。版本墙的根因不在任何单个包,而在分叉落后上游。
本批次的版本差距:
- 鸿蒙分叉最新:
oh-3.44.9-dev(HEAD=fe316cf7,2026-09-11),tag3.44.9+ohos-0.0.1-canary1; - 上游最新稳定版:
3.47.4(9584c671,2026-08-12 发布); - 官方 README 版本表预计 3.47 鸿蒙版 2026/12 才跟进——间隔约 4 个月。
这 4 个月里,上游 3.45/3.46/3.47 的生态包、新特性全部被挡在鸿蒙门外。本工程的选择是抢先同步,不等官方跟进:

上图四个象限就是本批次决策的完整逻辑:左上是版本墙的真实 pub get 报错(升分叉版本,不是去找上游安装包);右上是上游 3.44.9→3.47.4 的漂移规模——合计 2750 个文件变动,每一处都可能撞上鸿蒙适配;左下是「不同步」的代价(生态包用不上、特性代差、用户被迫降依赖版本)与「同步」的回报(一整条版本线与生态入口);底部一句话点题:风险面 = 上游改动 ∩ 鸿蒙适配的交集文件;同步不是搬代码,是重放一套「适配集」。
1.2 批次的三项交付物
- 同步:编译通过、测试通过,能用该 SDK 把 Flutter 项目编译成鸿蒙 HAP 包;
- 文档:本系列文章,边适配边写(你正在读的就是);
- Skill:适配成功后沉淀为可复用的自动化 skill,下一批次直接调用。
三项交付物里,第 1 项是目标,第 2、3 项是杠杆——没有文档,踩过的坑下一批还会再踩一遍;没有 skill,每次同步都是手工作坊。
二、版本基线:批次的四个坐标
2.1 基线表
一次同步批次由四个坐标完全确定,开跑前先钉死在纸上:
| 项 | 值 |
|---|---|
| 鸿蒙适配仓库 | atomgit.com/oh-flutter/flutter_flutter(当前主线;批次起点为 oh-3.44.9-dev) |
| 鸿蒙最新分支 | oh-3.44.9-dev(HEAD=fe316cf7,2026-09-11);tag 3.44.9+ohos-0.0.1-canary1 |
| 上游同步目标 | tag 3.47.4 = 9584c6713b324636289d067944a46fd6b49df14b(2026-08-12 稳定版) |
| 上游 3.44.9 基线 | tag 3.44.9 = 6b182d2c7585eba26d4edce0f97630effd256c33(2026-08-05) |
四个坐标里最容易忽略的是第四个:上游旧基线 tag(3.44.9)。它是「适配清单」的 diff 起点——没有它,就算不出鸿蒙侧到底改了哪些文件(第三章的 2263 文件清单就来自这个 diff)。
2.2 上游变化规模:2750 文件
3.44.9 → 3.47.4,上游自身的变化规模:
变化文件 2750:engine 1123 · packages 804 · dev 578 · examples 138 · docs 27
Dart revision:d684a576a6 → 1d1a730ef9(Dart 3.13.3)
engine revision:5a2a6a42 → 06a2e2a1
两个直接推论:
- engine 层是最大变化面(1123 文件)——适配工作重心必然落在 engine 嵌入层,这就是 Phase 3 要重打 826 个 engine 文件的由来;
- Dart 大版本跳了(3.12.2 → 3.13.3)——定制 Dart SDK 不能沿用旧的,必须从源码重建(第 6 篇 Phase 2 的最大发现)。
2.3 为什么选「全新分支」方案(不 merge)
拿到 3.47.4 基线后的第一个方案决策:不 merge 旧分支,而是开全新分支 + 适配集重放。
# 基线 = 上游 tag,全新分支
git checkout -b oh-3.47.4-dev 3.47.4
# 适配集 = 旧基线树级 diff 恢复的清单(第 6 篇 Phase 1 产出)
git apply --3way <适配集 diff>
不 merge 的三个理由:
- 历史干净、无合并债:新分支的每个提交都可审计,不存在 merge commit 里的「混合状态」;
- 冲突一次性暴露:三方重放时所有 API 漂移当场撞出来(Phase 2 的 13 处 flutter_tools 漂移就是这么暴露的),而不是散在后续 merge 里慢慢炸;
- 同一套打法可重放到下个版本:下一批次(3.47.4 → 3.5x)复用完全相同的「基线 + 清单 + 重放」流程——这是端到端同步 SOP 能参数化的前提。
2.4 基线核验:开跑前先验四个坐标
开跑前把四个坐标逐个从远端验一遍(不信任记忆里的值):
# 验上游目标 tag 与旧基线 tag
git ls-remote https://github.com/flutter/flutter.git refs/tags/3.47.4 refs/tags/3.44.9
# 验鸿蒙分叉分支的 HEAD
git ls-remote https://atomgit.com/oh-flutter/flutter_flutter.git refs/heads/oh-3.44.9-dev
返回的 SHA 与 2.1 节基线表逐一对账(本批次:3.47.4 = 9584c671... ✅、3.44.9 = 6b182d2c... ✅、oh-3.44.9-dev HEAD = fe316cf7 ✅)。任何一个对不上,先停下来查清——后面的 diff、重放、验证全部建立在这四个坐标上,坐标错一分,结果错一片。
三、适配点构成:2263 文件的全景
3.1 总盘:+192740 行与顶层分布
「鸿蒙侧到底改了什么」不是拍脑袋,而是从树上 diff 出来的。用旧基线树级 diff 恢复适配清单(命令见第 6 篇 Phase 1):
git diff --name-status 3.44.9 oh-3.44.9-dev > sync-data/ohos_adapt_list.txt
实测结果(与旧机调研值逐项对得上,清单即权威版本):
| 指标 | 值 |
|---|---|
| 总文件 | 2263 |
| 新增 A / 修改 M / 删除 D | 1738 / 522 / 3 |
| +行 / -行 | +192740 / -2018 |
| 顶层分布 | engine 826 · dev 633 · packages 421 · examples 265 · ci 41 · 其他 ~80 |
读这张表的方式:engine 826 + packages 421 是适配主体(约 65%),dev 633 主要是 flutter_tools 的 ohos 工具链与模板,examples 265 是示例工程,ci 41 是持续集成配置。这个分布直接决定了五阶段方案的切法(第六章)。
3.2 Framework 侧:421 文件的两种模式
packages/ 下 421 文件(251 改 + 151 增),核心是两种重复模式:
模式一:TargetPlatform 加 ohos 值,全部 switch 补 case。 平台判断的入口在 packages/flutter/lib/src/foundation/platform.dart,加一个枚举值之后,框架里所有 switch (TargetPlatform) 都要补 case TargetPlatform.ohos:(对齐 android 的行为)。这是数量最大、最机械的一类改动:
// 模式示意:上游的 switch 通常只有 android/ios/fuchsia/linux/macos/windows
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.ohos: // 鸿蒙侧补的 case,行为对齐 android
// ...
}
模式二:flutter_tools 新增独立的 lib/src/ohos/ 目录(12 个文件),把鸿蒙做成工具链的一等公民:
ohos_builder / hvigor / hvigor_utils / hdc_server
ohos_device / ohos_device_discovery / ohos_doctor
ohos_plugins_manager / ohos_sdk / ohos_workflow
application_package / build_env
这两个文件清单与第 1 篇 L6 层(工具链层 13 源文件)是同一件事的两个视角:L6 按「层」数,这里按「文件」数。
3.3 Engine 侧:826 文件 = 新增平台目录 + 构建体系
engine/src/flutter/ 下 826 文件(207 改 + 589 增),主体是新增:
shell/platform/ohos/ # 完整平台实现:BUILD.gn、napi、accessibility、
# external_view_embedder、flutter_embedding 等
testing/ohos/ # 引擎单测的鸿蒙运行端
run_ohos_unittest.py # 单测驱动脚本
注意「新增为主」这个结构:引擎适配不是重写公共逻辑,而是给引擎补一个 ohos 平台目录(第 1 篇「三层复用、一层重写」的引擎侧体现)。真正撞上公共引擎逻辑的改动是少数——而那少数,正是 Phase 3 里 15 个真冲突的高发区(第 7 篇)。
3.4 构建/发布体系:root 级文件
还有一类不显眼但缺一不可的适配点,散在仓库根级:
- 版本锁:
bin/internal/engine.ohos.version、engine.ohos.har.version——ohos 引擎与 HAR 的坐标,与上游engine.version平行存在; - 依赖与 CI:
DEPS_ohos(ohos 依赖锁定)、.ci_ohos.yaml(鸿蒙 CI 配置); - 变更日志:
CHANGELOG_OHOS.md——消费侧升级决策的权威清单(第 2 篇 5.2 节); - 合规:
OAT.xml、LICENSE_HW、LICENSE_KHZG——开源合规与许可声明。
3.5 勘误:OBS 地址的真实身份
原文档里有一句「artifacts 下载源华为云 OBS」,2026-09-15 补了勘误批注,口径更新为:
OBS 现仅为默认回退地址。 本分支实际由
bin/internal/dart-sdk-url.ohos的覆盖行改指 atomgit Release;
OBS 上那套工件是 3.44.9 / dart 3.12.2 时代产物,与本分支 kernel 138 不配套。
这条勘误的教训:工件下载源「名义地址」和「实际生效地址」可能是两套东西,判断 SDK 行为前先看覆盖行。完整的发布链路(版本锁、覆盖行、工件布局)是第 9 篇的主题。
3.6 清单文件解剖:2263 行怎么读
2263 文件清单本体是 sync-data/ohos_adapt_list.txt 一个纯文本文件,每行 git diff --name-status 格式(动作类型 + 路径):
M packages/flutter/lib/src/foundation/platform.dart
A packages/flutter_tools/lib/src/ohos/ohos_builder.dart
A engine/src/flutter/shell/platform/ohos/BUILD.gn
...
三个常用读法:
- 按顶层过滤:
awk '{print $2}' | cut -d/ -f1 | sort | uniq -c得到各顶层目录分布——3.1 节那张表就是这么算出来的; - 按动作类型过滤:
grep '^A'/grep '^M'/grep '^D'分别看新增/修改/删除——新增文件与修改文件的重放策略不同(新增多为整文件,修改走三方合并); - 按目录圈定工作集:
grep -E '^[AMD].*packages/'圈出 Phase 2 工作集(421 文件)——第 6 篇用的就是这条过滤。
清单是整批次的「单一事实源」:该重放多少、已重放多少、还差哪些,都拿它做差集。
清单丢了,批次等于失控——所以 G1 验证门的第一件事就是清单校验。
四、3.47 Breaking Changes:三个影响鸿蒙
4.1 影响鸿蒙的三项
3.47 的 Breaking Changes 里,有 3 项直接落在鸿蒙适配的交集文件上(⚠️ 标记):
- ⚠️ OpenGL ES render-to-texture 内容改为 top-down 存储——关联 ohos render/surface/texture 路径,「编译过 ≠ 渲染对」,方向正确性必须上真机/模拟器验证;
- ⚠️ semantics
header/headingLevel在 iOS/Android 行为变更——影响 ohos accessibility 的取数路径,语义朗读正确性同样挂真机验证; - ⚠️ 移除
describeEnum——鸿蒙代码若引用需迁移,全仓替换为enum.name类取法,编译期即可验证,是本批最干脆的一项。
4.2 待稳定项:不引入
另有三项上游尚未稳定的变更,本批次的决策是不引入(跟随上游稳定后再说):
DropdownButtonenabled 语义调整;material_ui/cupertino_ui拆包;- Android prebuilt flags。
「不引入」本身是一个需要记录的决策——否则下一批次的维护者会疑惑「为什么这三项没做」。
五、BC 适配表:5+7 项实测明细
上一章是「发现了哪些 BC」,这一章是「每一项怎么适配、验证到什么程度」。本表是 3.44→3.47 迁移期已实测确认的适配档案(非预测清单):Framework 侧条目在 Phase 2/3 迁移(编译链验证),Engine 侧条目全部来自 M2/M3 本地构建实测撞坑并修复。
5.1 Framework 侧(5 项)
| # | Breaking Change | 鸿蒙侧对策 | 状态 |
|---|---|---|---|
| 1 | OpenGL ES render-to-texture 改为 top-down 存储 | ohos/skia 纹理路径翻转逻辑已随同步迁移;方向正确性待真机/模拟器验证(编译过 ≠ 渲染对) | 已适配/验证挂起 |
| 2 | semantics header/headingLevel 行为变更 | ohos accessibility 取数路径随同步迁移,语义朗读正确性同挂真机 | 已适配/验证挂起 |
| 3 | 移除 describeEnum | 全仓迁移到 enum.name 类取法,编译通过 | 完成 |
| 4 | DropdownButton enabled 等(上游待稳定) | 不引入 | 不适用 |
| 5 | material_ui/cupertino_ui 拆包(上游待稳定) | 不引入 | 不适用 |
前两行「已适配/验证挂起」是最需要警惕的状态:代码迁了,但渲染/朗读正确性还没被真机证明。这类条目的销项只能发生在 Phase 5 的设备侧验证里(第 10 篇)。
5.2 Engine 侧(E1-E7,全部修复并验证)
| # | API 漂移 | 修法 | 出处 |
|---|---|---|---|
| E1 | Paint::CreateContents 扩参(ContentContext& + Geometry* + std::optional<Matrix>) | 测试 TU 重写为产物契约断言(MockContext 链上不可构造) | 06 P27b |
| E2 | FenceWaiterVK::AddFence 插入 submit_callback 参数 | 测试补占位 lambda | 06 P27b |
| E3 | impeller::Context 新增纯虚 FinishQueue() | 测试 fake 补 return false | 06 P27b |
| E4 | PlatformView::Delegate 新增纯虚 OnPlatformViewHitTest | fake 补 {.has_platform_view = false}(上游 ios test 同款) | 06 P27b |
| E5 | DlImage 抽象基类化,工厂迁到子类 DlImageSkia::Make | 两处调用点迁移 + 显式 include dl_image_skia.h(dl_sk_canvas.h 只给前向声明) | 06 P21/P27b |
| E6 | #define private public hack × libc++ <ranges> 硬错误(工具链升级放大,非上游 API 变更) | 宏前 #include <ranges> 预热;私有成员少走 friend+tunnel | 06 P22/P27b |
| E7 | fontmgr_ohos 端口被整端口移除(官方有意清理) | 2026-09-14 反转:采用华为 skia 方案恢复端口(见 5.3) | 06 P28/P29 |
E1-E4 有一个共同规律:全是测试文件的 API 契约漂移(fake/mock 跟不上上游接口变化),生产代码侧的漂移编译期即暴露、相对好修。这条规律被写进了下一批次的预判(5.3 节末尾)。
5.3 E7 反转:字体端口的故事
E7 是本批次最有戏剧性的一条,因为它反转了一次已作出的决策:
- 同步过程中发现
fontmgr_ohos(Skia 的鸿蒙字体管理端口)在 3.47 里被整端口移除,官方口径是有意清理; - 初判「不做恢复」——反正官方清理了,跟着清理省事;
- 2026-09-14 反转:不恢复 = 文字/图标全不可见(编译零报错的静默故障),「省事」变成「不可用」。最终采用华为 skia 方案恢复端口:端口源码经 attachment 机制托管落盘(skia 树零 tracked 文件、不能就地改),GN 开关 + freetype + 引擎侧胶水一并恢复,jsoncpp 仍走独立代理 target;端口源取自 CPF-Flutter/fluttertpc_skia 镜像,含 4 处必需的 include 适配。
这个反转直接催生了第 10 篇(字体图标静默故障诊断 SOP)——每个批次、每次发布都要单独跑字体检查,就是这条教训的制度化。
5.4 下一批次的预判
从 E1-E7 提炼的三条预判,供下一同步批次直接使用:
- 引擎侧漂移集中在测试 TU 的 API 契约面(E1-E4 全是测试文件)——先把测试 fake 的接口对齐排进 Phase 3 清单;
DlImage工厂迁移是「抽象类化」趋势的一部分——下一批次开跑前先grep DlImage::Make与dl_image相关 include;- 伏笔:jsoncpp 代理 target 引用 spirv 自带的 amalgamated 1.6.2,若上游 jsoncpp 版本升级,需同步确认 vsync 代码的 API 兼容。
# 下一批次开跑前的两条预备 grep(预判 2 的落地)
grep -rn "DlImage::Make" engine/src/flutter/
grep -rln "dl_image" engine/src/flutter/ --include="*.h" --include="*.cc"
5.5 十二条目的记忆锚点
5+7 共 12 条 BC 适配档案,按「状态」分三堆记,比逐条背有效得多:
- 已销项(3 条):Framework #3(
describeEnum移除,编译期验证)+ E5、E6(DlImage工厂迁移、private publichack,M2/M3 实测修复); - 挂真机验证(2 条):Framework #1(top-down 纹理翻转)、#2(semantics 行为变更)——代码迁了,渲染/朗读正确性等设备侧裁决;
- 不适用(2 条)+ 测试契约漂移(4 条)+ 静默故障专项(1 条):两条「不引入」是决策记录;E1-E4 全是测试 fake 跟接口;E7 单独立项成第 10 篇。
下一批次的 BC 表照这个三堆结构填:先问「销项没有」,再问「挂在哪」,最后问「要不要专项」。
六、五阶段同步方案:分工与验证门
6.1 Phase 0-5 总表

上图是完整作战图:上半是「全新分支 + 适配集三方重放(不 merge)」的打法与适配 delta 实测;下半是五阶段与各自的验证门。展开成表:
| Phase | 内容 | 工作量 | 验证门 |
|---|---|---|---|
| 0 | 环境准备(新机 arm64、88GB、ninja/DevEco/hdc、代理) | 已完 | 工具链连通 |
| 1 | 基线:fetch 上游 tag,checkout -b oh-3.47.4-dev,恢复适配清单 | 低 | G1 清单全对上(2263 文件校验) |
| 2 | Framework:platform.dart → switch 补 case → 移植 flutter_tools/ohos → Dart 源码构建 | 高 | G2 flutter analyze 0 error |
| 3 | Engine:移植 shell/platform/ohos → BC 适配 → testing/ohos → 构建 har | 最高 | G3 契约 16 项通过 |
| 4 | 构建/发布:版本锁、cache.dart 接线、覆盖行、CHANGELOG、合规 | 中 | G4 工件 URL 可达 |
| 5 | 验证:framework 单测 + engine 单测 + flutter build hap 真机冒烟 | 中 | G5 真机 1723/1723 全绿 |
6.2 验证门:不过门不进门
五阶段方案的灵魂不是「分五步」,而是每阶段一道验证门,不过门不进下一阶段,问题就地止损:
- G1(清单):适配清单 2263 文件与旧机调研值逐项对上——清单错,后面全错,所以它是第一道门;
- G2(analyze):
flutter analyze全量 0 error——Dart 层没绿,engine 层开工没有意义; - G3(契约):engine 与 framework 的 16 项契约对齐检查——接口不对齐,构建出来也是坏的;
- G4(URL):发布工件的下载 URL 实测可达——工件挂了,消费侧全部白搭(第 9 篇的主题);
- G5(全绿):真机引擎单测 1723/1723 + 三档 HAP 冒烟——设备侧证据是最终裁决(第 10 篇的主题)。
验证门是该阶段「过/不过」的判据,不是「尽量做到」的建议。
本批次 29 个编号坑(P1-P29)里,相当一部分是「没等门绿就往下走」的代价。
6.3 Phase 与本系列篇目的对照
五个 Phase 与生产侧后续篇目一一对应,阅读时可以按需跳转:
| Phase | 篇目 | 核心内容 |
|---|---|---|
| 1 基线建立 | 06 | 代理 HTTP/1.1 修障、浅克隆、清单恢复校验 |
| 2 Framework + Dart | 06 | 421 文件三方重打、Dart SDK 源码构建(6 补丁) |
| 3 Engine | 07 | 826 文件重打、15 个真冲突裁决、契约对齐 16 项 |
| 4 构建/发布 | 09 | 版本锁、cache.dart 接线、覆盖行、11 个工件(引擎 5 + Dart SDK 4 + patched_sdk 2) |
| 跨批次方法论 | 05(本篇 §七) | 端到端 SOP、G0-G5 验证门、P1-P29 索引、错误签名查表 |
| 5 验证与冒烟 | 10 | M1-M5 验证门、三档引擎、设备侧证据;P1-P29 明细散在 07/08/10,权威索引见本篇 §7.9 |
| 专题:字体 | 10 | 静默故障分层诊断、三层证据链 |
6.4 第二条编号轴:里程碑 M0-M5
本篇之外,第 8、9、10 篇还有一条里程碑(Milestone)轴在用它,读者会看到「M2 实录」「M5 追加」这类说法。它和 Phase 是两个不同的轴:Phase 是计划视角(这一阶段交付什么),Milestone 是执行视角(一个可验证的状态点,达成即冻结证据)。同批次实测对照:
| Milestone | 状态点 | 判据 | 对应 Phase | 明细篇目 |
|---|---|---|---|---|
| M0 | Dart SDK 就位 | 源码构建的 dart-sdk + 打补丁的 frontend_server 可用 | 2 | 06 |
| M1 | 构建图完整 | gn gen 通过 + 三档 out/ 目录成型 | 3 | 08 §二 |
| M2 | 引擎编得出来 | ninja 0 FAILED,四 target 齐备 | 3 | 08 |
| M3 | 端到端跑得起来 | flutter build hap 出包 + 设备侧安装启动 + 单测跑通 | 5 | 10 §二、§三 |
| M4 | 发得出去 | 11 个工件上 Release、11 条覆盖键生效、用户零操作装到 | 4 | 09 |
| M5 | 验得干净 | 真机单测全绿 + 三档引擎 + 字体端口三档在位 | 5 | 10 §三、§四、§六 |
两个轴故意不重合:M4(发布)排在 M3(冒烟)之后,但 Phase 4 排在 Phase 5 之前——因为本批次实际是先冒烟确认引擎可用,才敢发布,发布后又回到设备侧做 M5 全量复核。这个错位是真实执行顺序,不是笔误。
引用规则:说"该交付什么"用 Phase,说"做到了哪一步"用 M。第 8/9/10 篇的小结都标了自己对应的 M 段(M2 / M4 / M5)。
七、端到端同步 SOP:可参数化的执行序
7.1 为什么第六章之外还要一节
第六章回答的是「谁在什么阶段交付什么、过不过门」;本节回答「下一批次照着敲什么命令」。同一批 Phase,两个视角:
- 第六章是分工表——给评审和排期看;
- 本节是执行序——给实际操作的人看,每一步带验证门,且全部变量参数化。
3.44.9 → 3.47.4 那一次的现场记录在第 6、7 篇;本节把它们的做法抽出来,去掉批次特有的数字。Phase 编号与 §6.1 完全一致(0-5),不另起一套。
7.2 新批次变量表:先填这张表,再动手
| 变量 | 从哪取 | 3.47.4 批次的实例值 |
|---|---|---|
{{UPSTREAM_TAG}} | 上游 release 页 / git ls-remote --tags upstream | 3.47.4 = 9584c6713b324636289d067944a46fd6b49df14b |
{{PREV_TAG}} | 上一批用的上游 tag | 3.44.9 = 6b182d2c7585eba26d4edce0f97630effd256c33 |
{{PREV_OHOS_BRANCH}} | 上一批的鸿蒙分支 | oh-3.44.9-dev |
{{NEW_OHOS_BRANCH}} | 命名惯例 oh-<tag>-dev | oh-3.47.4-dev |
{{DART_REV}} | 新 tag 的 DEPS 里 dart_revision | 1d1a730ef9(= Dart 3.13.3) |
{{ENGINE_REV}} | 新 tag 的 bin/internal/engine.version | 06a2e2a1 |
工作根目录:本 SOP 的相对路径一律以
$ROOT(flutter_flutter/的父目录)为基准。注意docs/、scripts/、sync-data/都在$ROOT下、不在 git 仓库里——只在仓库里搜会看不见它们。
7.3 Phase 0 预检:第一道门是「tag 真的存在」
cd $ROOT/flutter_flutter
# ① 先确认目标 tag 真实存在 —— 这一步不能省
git ls-remote --tags upstream | grep -F "{{UPSTREAM_TAG}}"
# ② 网络:本地代理会杀死 HTTP/2 大包(上批最大坑)
git config --global http.version HTTP/1.1
# ③ 磁盘:engine/src/out/ 三档 + dart 源码构建 + 全量对象,上批实测 88GB 空闲起步
df -h /System/Volumes/Data
# ④ 工具链
export PATH="$ROOT/depot_tools:/opt/homebrew/opt/llvm@19/bin:$PATH"
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk
⚠️ 这是本 SOP 的第一道门,也是实测踩过的坑:曾在未验证的情况下按「3.48.0 已发布」整批作业,实际上游当时只有
3.48.0-0.x.pre预发布版——照着不存在的目标做,全部结论作废。ls-remote无输出就停下来,向人要准目标版本。
验证门 G0:ls-remote 命中目标 tag ✅;git config --get http.version = HTTP/1.1 ✅;磁盘 ≥ 80GB ✅;python3 / ninja / gn / llvm@19 可用 ✅。
7.4 Phase 1 基线:浅克隆 + 三方 diff 出风险面
git fetch --depth 1 upstream "refs/tags/{{UPSTREAM_TAG}}:refs/tags/{{UPSTREAM_TAG}}"
git checkout -b {{NEW_OHOS_BRANCH}} {{UPSTREAM_TAG}}
# 适配集打包:--binary 必须放在 -- 之前,否则被当 pathspec、二进制补丁静默残缺
git diff --binary {{PREV_TAG}} {{PREV_OHOS_BRANCH}} -- packages/ > /tmp/adapt_packages.patch
git diff --binary {{PREV_TAG}} {{PREV_OHOS_BRANCH}} -- engine/ > /tmp/adapt_engine.patch
# 适配 delta 与交集清单(决定后面的工作量与风险面)
git diff --name-only {{PREV_TAG}} {{PREV_OHOS_BRANCH}} | sort > $ROOT/sync-data/fork_delta.txt
git diff --name-only {{PREV_TAG}} {{UPSTREAM_TAG}} | sort > /tmp/upstream_delta.txt
comm -12 $ROOT/sync-data/fork_delta.txt /tmp/upstream_delta.txt > /tmp/intersection.txt
wc -l $ROOT/sync-data/fork_delta.txt /tmp/intersection.txt
验证门 G1:git rev-parse {{UPSTREAM_TAG}} 与 ls-remote 的值一致 ✅;工作树 clean ✅;适配清单 2263 文件与调研值逐项对上(§3.1 的 --name-status 口径)✅;交集清单已落盘 ✅。
两个口径别混:
--name-status的适配清单是 2263 文件(第三章,含dev/examples/ci/);而git diff --name-only {{PREV_TAG}} {{NEW_OHOS_BRANCH}}只数当前分支实际落地的 delta,上批是 1263 文件(engine 836 / packages 423 / bin 4)。同口径量级对不上,就要查是不是 fetch 不完整。交集清单才是本轮真正的风险面:只有双方都改过的文件才可能真冲突。
7.5 Phase 2 Framework 重打:unmerged ≠ 内容错误
git apply --3way /tmp/adapt_packages.patch
git diff --diff-filter=U # 停在 unmerged 索引态的文件
3-way 以当前 HEAD(= 新上游 tag)为 “ours”:鸿蒙单侧改动自动干净落入,只有双方都改同一区域才留冲突。上批 421 文件重打后磁盘上 0 冲突标记、但有 14 个文件停在 unmerged 索引态,内容已正确,git add 即清。
重点裁决面是 flutter_tools——上批实测 13 处漂移的重灾区(完整表见第 6 篇):reporting/ 目录删除、LinkHooks / combinedResult 类名迁移、_getPrebuiltTarget 穷尽匹配补 ohos case、build_system/targets/native_assets.dart 变量改名。新批次先读上游文件再移植,不要盲打补丁。
# 改过 flutter_tools 源码后必须删快照,否则跑的还是旧工具
rm -f bin/cache/flutter_tools.snapshot bin/cache/flutter_tools.stamp
验证门 G2:./bin/flutter --version 横幅完整输出(新版本号 + Dart 版本)✅;flutter analyze 全量 error = 0 ✅。
7.6 Phase 2 尾:Dart SDK 必须从源码构建
注意顺序:Dart SDK 必须先就位,否则 flutter_tools 编译时报
ohosArm/isOhosMember not found。机理见第 6 篇,这里只给执行序。
官方 dart JIT 二进制内嵌 platform kernel,往 bin/cache/dart-sdk 的 lib/ 里打补丁对运行时零影响——必须从源码构建。
# 1) 检出 {{DART_REV}}(.gclient 必须在父目录,checkout 目录名必须恰为 "sdk")
gclient sync
# 2) 应用 ohos 补丁集(可重跑脚本已固化;上批为 6 文件)
bash $ROOT/scripts/patch_and_build_dart_ohos.sh
# 产物:xcodebuild/ReleaseARM64/dart-sdk → 替换 bin/cache/dart-sdk(原版另存)
# 3) frontend_server 同树重编,product 配对部署到 bin/cache/dart-sdk-ohos/
验证门:dart --version 为新版本 ✅;import 'dart:ffi'; print(Abi.ohosArm) 通过 ✅;frontend_server --target-os=ohos 不再报白名单错误 ✅。
⚠️ 两个名字极易混(都在
bin/cache/,只差一个下划线):
bin/cache/engine.stamp← 引擎版本 SHA,由update_engine_version.sh从bin/internal/engine.version生成,同步上游时自动更新,别手改;bin/cache/engine_stamp.stamp← 另一个 cache 工件的标记文件,与它无关。另注:
bin/internal/下没有engine.stamp这个文件(实测不存在),别去那里找。
换 Dart 版本时还要记住第 9 篇 §6.5 那条:bin/cache/dart-sdk-ohos 不会被覆盖机制自动更新(判据是"文件不存在",与引擎工件行为相反),必须手工 rm -rf。
7.7 Phase 3 Engine 重打与构建:工作量主体
git apply --3way /tmp/adapt_engine.patch
git diff --diff-filter=U
冲突裁决的两分法(上批 15 个真冲突定型,判据与逐条裁决见第 7 篇):
| 类别 | 判据 | 处置 |
|---|---|---|
| 格式吸收类 | 上游自己完成了同名重构,鸿蒙侧改动被吸收 | 取 OURS(新上游),用双向归零验证器确认:git diff --cached <鸿蒙侧> -- f 与 git diff --cached <新上游> -- f 双向跑,吸收文件对上游侧必须 = 0 行 |
| 手合类 | 双方改的是不同语义,都要保留 | 逐项 API 移植(上批 7 个:allocator 的 OH_RESTRACE、capabilities 的 OHOS 扩展、mock_vulkan 记账、typographer 整函数重建…) |
典型陷阱:
git diff3的行对齐启发式会把只属于一侧的标识符混进"公共区",逐 hunk 拼装不可行 → 遇到这种要整函数重建并与两侧原始版本逐行比对(上批 typographer 即此)。补丁"改写原语句"时要对上游 diff 做结构性检查,防括号吞并(P11)。
构建(规范化入口是 engine/ohos wrapper,不是手搓 gn/ninja):
cd $ROOT/flutter_flutter/engine # cwd 必须是引擎编译根,ohos.py 会强制检查
./ohos -n config -t debug profile release # gn gen
./ohos -n compile -t debug profile release # ninja
./ohos -n har -t debug profile release # 产 har
三条硬规则(详见第 8、9 篇):
--llvm18不要用——它把 toolchain 指到 DevEco 的 clang 15,编不过 zlib;args.gn必须落到custom_toolchain = "/opt/homebrew/opt/llvm@19";args.gn在未跟踪的out/里,换机即丢,且out/已存在时增量gn gen不会补新 args;- 新批次会撞的坑先查 §7.9 的索引表,别从头排。
验证门 G3:三档 out/ohos_<mode>_arm64/libflutter.so 产出 ✅;ninja 0 FAILED ✅;契约对齐 16 项通过 ✅。
7.8 Phase 4 发布 / Phase 5 验证 / 收尾
Phase 4(构建发布) 的完整流程在第 9 篇:引擎侧打包 5 个 zip(3 个 har + 2 个宿主 gen_snapshot)、连同 2 个平台 dill、再备齐 Dart SDK 侧 4 个包(macOS / Windows 各一套),共 11 个附件 → 新建 tag → 传附件 → 改 bin/internal/dart-sdk-url.ohos 的 11 条覆盖键 → 提交推送。发布动作不改三个 *.version 锁文件,推进信号是覆盖行 URL。
Phase 5(验证) 的判据在第 10 篇,两个数别混:
- 真机 1723 全绿(基线用这个数);
- 模拟器 1703 通过 / 20 失败——那 20 项已查明是纯环境性(无 Vulkan 设备 / QoS 差异),与适配无关。拿模拟器数字当基线会误判成回归。
字体端口在不在是 Phase 3-4 最容易被静默丢掉的东西——它丢了编译不会报错,只是所有字形消失。每次同步后都要走一遍第 10 篇 §五 的分诊流程,别等出 HAP 才发现。
收尾:Breaking-changes 分析归档进本系列的 §五 那张表;更新版本基线与当前状态文档;新踩的坑按 Pxx 编号追加进 §7.9 索引表,并把"错误签名 → 修复"一行加进自己的 pitfalls 速查。
⚠️
release-notes/changelog/在当前分支已不存在(实测git ls-files release-notes/= 0 行,目录也没有)——照着旧路径建目录会白做。
7.9 P1-P29 全索引:生产侧坑的一站式归属
本批次 29 个编号坑的权威索引(明细在指向的篇目里,本表只做归属与一句话定性):
| 编号 | 一句话 | 类别 | 明细 |
|---|---|---|---|
| P1 | 旧 obj/*.ninja 与 build.ninja 组成 stale 混合图(症状最迷惑) | 依赖树 | 08 §2.1 |
| P2 | SkLog_ohos.cpp 悬空引用——同步产物,非事故 | 依赖树 | 08 §2.2 |
| P3 | esbuild 预编译组件缺失(CIPD 少装) | 依赖树 | 08 §2.3 |
| P4 | libcxx 缺 shared/fp_bits.h:漏拉一个子依赖 | 依赖树 | 08 §2.4 |
| P5 | libcxx 的 Clang 18 硬门槛(本轮最关键) | 工具链 | 08 §3.1 |
| P6 | LLVM 23 太新:-Wdeprecated-attributes 毒化老第三方代码 | 工具链 | 08 §3.2 |
| P7 | diff 为零的文件仍引用被上游删掉的 SampleCount::kCount2 | 源码适配 | 07 §6.1 |
| P8 | 同步新写文件缺尾换行,-Werror,-Wnewline-eof | 源码适配 | 07 §6.6 |
| P9 | 重命名类变更:先认上游新语义再决定去留 | 源码适配 | 07 §6.2 |
| P10 | 私仓 pin 差异 + vendored 头缺失(最长的一战) | 源码适配 | 07 §6.3 |
| P11 | OHOS 补丁吞括号(#ifdef 配平错,报错点离根因很远) | 源码适配 | 07 §6.6 |
| P12 | GetRenderTargetView 上游加参,fork override 未跟随(虚函数) | 源码适配 | 07 §6.7 |
| P13 | QueueSignalReleaseImageOHOS 失去调用方,按上游删除 | 源码适配 | 07 §6.7 |
| P14 | device_holder 重复定义——补丁贴在新版析构前面 | 源码适配 | 07 §6.7 |
| P15 | sysroot 的 CMSG_NXTHDR 宏触发 -Wsign-compare | 源码适配 | 07 §6.7 |
| P16 | VK_USE_PLATFORM_OHOS 的 include-guard 时序(同批有的 TU 正常) | 源码适配 | 07 §6.7 |
| P17 | 华为 develop 分支私有依赖 SkGlyphRasterWorkerSlot.h | 源码适配 | 07 §6.7 |
| P18 | SliceViews 上游加参漏跟随(自由函数版,含级联假象) | 源码适配 | 07 §6.7 |
| P19 | 字体端口"半同步"残骸的整链清理(7 文件) | 源码适配 | 07 §6.4 |
| P20 | 删多了:GPU 栅栏路径的 Queue 方法被误删 | 源码适配 | 07 §6.5 |
| P21 | 没跟上:FenceWaiterVK::AddFence 扩参 | 源码适配 | 07 §6.5 |
| P22 | 测试面 #define private public 撞上 libc++ <ranges> | 源码适配 | 07 §6.8 / 08 §5.2 |
| P23 | flatbuffers × _GNU_SOURCE × musl strto*_l 函数面 | 构建体系 | 08 §4.1 |
| P24 | 链接三件套:host clang 驱动 + DevEco runtime 桥接 | 构建体系 | 08 §4.2 |
| P25 | wasm-opt 缺异常运行时:libcxxabi 的 OHOS 分支必须编真身 | 构建体系 | 08 §4.3 |
| P26 | har 双修复:SDK 扫描层级 + API 26 面签名差异 | 构建体系 | 08 §4.4 |
| P27 | libflutter.so 的 Json::* 未定义——jsoncpp 幽灵依赖 | 收尾 | 08 §5.1 |
| P27b | 测试面漂移的五个规律(最便宜的上游 API 探测器) | 收尾 | 08 §5.2 |
| P28 | 字体端口恢复(P19/E7 方向反转,编译期零报错) | 发布/验收 | 10 §四 |
| P29 | 三档引擎:a 装错包 / b marker 冲突 / c AOT 缓存在 .dart_tool/ | 发布/验收 | 10 §六、09 §6.6 |
消费侧另有 CP1-CP14 一套编号(用别人发好的 SDK 时踩的坑),权威总表在第 3 篇 §六。两套编号不互相复用。
7.10 错误签名 → 出处:按报错文字查表
| 错误签名 | 出路 |
|---|---|
全量 clone curl 18 transfer closed / early EOF | §7.4 前置:代理杀 HTTP/2,http.version=HTTP/1.1(第 6 篇) |
--binary 补丁打上去二进制文件残缺 | §7.4:--binary 误放 -- 之后被当 pathspec |
git apply 后大批文件停在 unmerged 索引态 | §7.5:内容可能已对,先看 git diff --diff-filter=U 再决定 |
Member not found(Abi.ohosArm) | §7.6:dart JIT 内嵌 platform kernel,必须从源码构建 SDK |
Platform.isOhos undefined 但 SDK 正常 | 第 6 篇:sky_engine/lib 是独立镜像,也要补补丁 |
flutter_tools 报 LinkHooks / combinedResult | 第 6 篇 13 处漂移表;先确认 Dart SDK 已就位 |
| 改 flutter_tools 后行为没变 | §7.5:删 bin/cache/flutter_tools.snapshot + .stamp |
no member named 'kCount2' 一类符号缺失 | P7 / P11 / P17:符号级同步 ≠ 文件级同步(第 7 篇 §六) |
gn gen 报 SwiftShader / zlib / libcxx 类错 | 第 8 篇 §二、§三(依赖树 + 工具链定版) |
链接报 undefined symbol 且来自系统库 | 第 8 篇 §四(musl 函数面与交叉链接三件套) |
compatibleSdkVersion ... cannot be lower than | 第 10 篇 §2.2:读 DevEco sdk-pkg.json 取精确串,别猜 |
--target-os=ohos 被拒 | 第 10 篇 §2.2:frontend_server snapshot 三段式重编,product 配对 |
Unexpected Kernel Format Version 130 (expected 138) | 第 9 篇 §1.3 / §6.1:覆盖行未生效 |
| 三档产物正常但 profile 一启动就 FATAL | 第 9 篇 §6.6 / 第 10 篇 §6.1:patched_sdk 装成产品档 dill |
| 反复重下 patched_sdk | 第 9 篇 §6.7:两个条目共用一个 .ohos-override-url 标记 |
清了 build/ohos/ 但 AOT 没重建 | 第 10 篇 §6.3:AOT 快照缓存在 .dart_tool/flutter_build/ |
| 文字 / 图标全不可见 | 第 10 篇 §五(专属诊断流程,编译期无任何报错) |
| 改了覆盖行但已装机器没反应 | 第 9 篇 §5.3:重传了同名附件,必须换新 tag |
7.11 流程通过判据与未验证项
七个 ✅ 全满足才算这批同步做完:
- Phase 0 的 tag 存在性已验证(不是假设);
- 适配集重打完成,冲突全部裁决且吸收类经双向归零验证;
flutter analyzeerror = 0;./bin/flutter --version横幅正常;- 三档引擎构建 0 FAILED;字体端口三档均在位(分诊见第 10 篇);
- 设备侧单测与三档 HAP 渲染通过(基线用真机数字);
- 第 9 篇的发布前回归清单全过;
- 文档与坑索引已更新。
本 SOP 的未验证项(不要当成已确认的步骤):
scripts/resolve_conflicts.py/merge7.py的 ours/theirs 语义是 3.47.4 批次写死的,冲突清单不同就要小改,未在新批次验证过;scripts/patch_and_build_dart_ohos.sh的补丁锚点以 Dart 3.13.3 树为准,换 Dart 版本要改锚点;package_ohos_engine_artifacts.sh的目录名与 LICENSE 源路径未在新批次验证;- 「354 个未碰撞文件一键落盘」上批属实但本轮未跑。
7.12 大批次之后:3.47.5 → 3.47.8 的小批次长什么样
本篇正文的 2263 文件是「跨三个 minor 版本的大批次」。真实节奏里更多是一两个文件的小批次——3.47.4 之后到 3.47.8 一共发了 4 个正式 tag,实际形态如下(数字取自 bin/internal/dart-sdk-url.ohos 的批次注释、各 tag 的覆盖文件原文,以及 Release 的 assets 清单):
| 批次 tag | 发布时刻 | 上游区间 | 本分支实际动作 | 自传附件 / 覆盖键 |
|---|---|---|---|---|
3.47.5-ohos-1.0.0 | 09-23 23:57 | 3.47.4 → 3.47.5 | Dart 升到 3.13.4(kernel 仍 138);引擎 C++ 层在该区间无变化 | 11 / 9 |
| —(3.47.6 未独立发布) | — | 3.47.5 → 3.47.6 | 上游全为 iOS 改动,与 OHOS 无关,并入下一批 | — / — |
3.47.7-ohos-1.0.0 | 10-13 20:09 | 3.47.6 → 3.47.7 | 上游仅 iOS(SemanticsObject 无障碍修复 + iOS PlatformView 测试),engine/src 无 OHOS 变更 → 附件逐字节重挂载;覆盖文件首次加两条 Windows Dart SDK 键 | 11 / 11 |
3.47.7-ohos-1.0.1 | 10-21 15:56 | — | 纯框架:flutter_tools 新增 OHOS 自动签名 lib/src/ohos/signing/(第 4 篇,提交 f2651e0b91 同日 11:00) | 11(重挂载)/ 11 |
3.47.8-ohos-1.0.0 | 10-24 20:59 | 3.47.7 → 3.47.8 | 纯框架:上游合并 6 文件 +221/−79 + 本分支「设备未连接分级排查」 | 11(重挂载)/ 11 |
「附件 11 / 键 9」这个差值本身值得记一条:Windows 的 Dart SDK 包早就传上 Release 了,覆盖文件里却还没有键——上传了但没人能下到。第 9 篇 §5.7 把这类失配列成了发布前的必查项。
3.47.8 这一批的全部代码改动(可逐条核对,原文见 Flutter 3.47.8-ohos 1.0.0 ReleaseNote.md):
- 上游两处修复:
packages/flutter_tools/lib/src/resident_runner.dart(117 行,debugDumpFocusTree/debugDumpLayerTree在vmService或uiIsolate为 null 时不再抛异常,上游 #194740);packages/flutter_tools/lib/src/flutter_plugins.dart(22 行,插件软链接损坏时安全处理,避免FileSystemException,上游 #194578); - 两个版本锁随上游动:
bin/internal/engine.version→cf636b1dfb818dd6a3ff16e390e93b1a036969c8,DEPS的dart_revision→416e33b0ffaef062a60ec966bb8c82ed2b83f128(只影响引擎源码构建,不改已发布工件); - 本分支新增:鸿蒙设备未连接时的分级排查提示——
OhosDeviceIssue(hdcNotAvailable/noDevices/connectFailed)、DeviceDiscovery.noDevicesHint(默认null,纯 Android/iOS 工程不受影响)、flutter doctor增加hdc list targets: N 台鸿蒙设备一行,并补 8 个单测(ohos_device_discovery_test.dart6 个 +ohos_doctor_test.dart2 个); - 引擎侧零变更:
engine.ohos.version(10a8d012d8)、engine.ohos.har.version(e068c218c3)、Dart 3.13.4 全都没动,11 个附件与 3.47.7-ohos-1.0.1 逐字节相同,只是重挂到新 tag。
于是小批次的 SOP 会塌缩成三步:合上游 → 跑框架侧验证门(flutter analyze + 上游改动涉及的 plugins_test.dart / terminal_handler_test.dart 共 181 个用例 + 本分支新增 8 个单测)→ 开新 tag、重挂载 11 个附件、把 11 条覆盖键指过去。三方重放、冲突裁决、三档 ninja 这些重型环节全部跳过,唯一不能跳的还是"换新 tag"(原因见第 9 篇 §5.3:同名重传对已装机器静默无效)。
八、环境与风险
8.1 执行环境:为什么换了新机器
本批次没有沿用旧机,而是迁移到全新设备——旧机 x86_64 只剩 48GB 磁盘,扛不住大仓库克隆与构建:
macOS 15.4.1 arm64(迁移自 x86_64 旧机,交叉编译顾虑解除)
磁盘:88GB 空闲
工具:git 2.39.5 · python3 3.9.6 · clang 17 · ninja 1.13.2 · node 20 · brew
鸿蒙:DevEco Studio 26.0.0 Release + hdc(OpenHarmony SDK / API 26)· fvm ohos = 3.44.9(批次基线)
代理:http 127.0.0.1:1087 / socks5 127.0.0.1:1080
连通性:github / atomgit / 华为云 OBS 均通
arm64 这一点值得单独提:旧机 x86_64 构建 arm64 目标要走交叉编译,多一类无谓故障;换机后「本机架构 = 目标架构」,构建路径直接简化。
8.2 三大风险与对冲
开跑前记录在案的风险(含事后看是否兑现):
- engine 1123 文件变化,embedder API 兼容性待排(主要风险)——兑现:E1-E7 全部是这类漂移,被 Phase 3 的契约对齐与 15 个真冲突裁决接住(第 7 篇);
- 全新分支 = 2263 文件适配重打,需清单驱动避免遗漏——兑现方式:G1 验证门(清单逐项校验),重打后磁盘 0 冲突 + 14 个 unmerged 索引态文件全部
git add销账(第 6 篇); - 官方 2026/12 跟进可能先发布,存在版本竞争——对本工程无实质影响,目标是对齐上游而非抢时间窗。
九、常见问题 FAQ
9.1 这篇写的是 3.47.4,现在安装该用哪个版本?
当前正式发布版是 3.47.8-ohos-1.0.0,新项目安装与验收都用它;本篇的 3.47.4 是 2026-09 的历史同步批次,保留它是为了讲清一次完整同步的决策链。两者同属 3.47 线,Phase 划分、验证门与踩坑模型通用。消费侧安装见第 2 篇(fvm 不认 tag,需把 tag 浅克隆到 ~/fvm/versions/ohos/);生产侧换批次时只需替换四个坐标:旧基线 tag、上游目标 tag、分叉分支、engine / Dart revision。
9.2 为什么不直接 merge 上游,而要用「全新分支 + 三方重放」?
merge 会把「上游 2750 个变化」和「鸿蒙 2263 个适配」揉进一个巨大的合并提交,冲突散落在后续提交里慢慢爆,且无法逐项审计。全新分支 + git apply --3way 重放的好处是:冲突一次性暴露、每个提交可审计、适配清单可复用。代价是要自己维护清单和补丁集——这正是本篇(§6.2 的 G1 验证门 + §7.4 的清单恢复)与第 6 篇要解决的部分。
9.3 上游 2750 文件、鸿蒙适配 2263 文件,是什么关系?
2750 是上游 3.44.9→3.47.4 自身的变化文件数;2263 是鸿蒙分叉相对上游旧基线改过的文件数(+192740 行)。两者不是同一批文件:真正的工作量是交集——上游改过、且鸿蒙也改过的文件,必须逐个三方重放并裁决冲突;不相交的部分按清单直接搬。engine 层交集最大(826 文件),所以 Phase 3 最重。
9.4 Breaking Changes 那 12 条怎么验证,能直接照抄结论吗?
不能照抄。BC 表是本批次实测档案:5 条已销项、2 条挂真机、其余是决策记录、测试漂移或静默故障专项。换版本后要按同样口径重跑:flutter analyze 全量 0 error(G2)、framework 单测、engine 契约对齐(G3)、HAP 冒烟(M1-M5),并保留设备侧证据。验证门的具体清单见第 10 篇 §七。
9.5 复现这个批次需要什么环境?
- Flutter OH 基线:
3.44.9(批次起点),目标上游3.47.4,当前发布版为3.47.8-ohos-1.0.0; - DevEco Studio 26.0.0 Release,OpenHarmony SDK / API 26(提供 hvigor / ohpm / hdc / JBR);
- macOS arm64、≥88GB 空闲磁盘、git / python3 / clang / ninja / node;
- 有代理时先
git config --global http.version HTTP/1.1,否则大包 clone 会断。
完整的环境变量与工具链配置见Flutter OH 环境搭建指导。
9.6 仓库地址统一用哪个?
当前统一用 atomgit.com/oh-flutter/flutter_flutter。早期文章里的 CPF-Flutter、openharmony-tpc 链接是历史仓库,只用于追溯旧提交;新克隆、新 CI 配置不要再指向它们。
十、本篇小结与系列导航
把本篇的总图压缩成五句话:
- 同步的动机是版本墙:分叉落后上游约 4 个月,生态包集体不可用;
- 批次的规模是上游 2750 文件变化 × 鸿蒙 2263 文件适配集,交集才是风险面;
- 打法是全新分支 + 三方重放(不 merge),清单驱动、五阶段、每阶段一道验证门(G1-G5);
- BC 的口径是已实测档案:12 条里 5 条销项、2 条挂真机、其余是决策记录/测试漂移/静默故障专项;
- 最大的单项教训是 E7 字体端口反转——「编译零报错 ≠ 可用」,字体检查从此是每个批次的固定动作;
- 第七章把这套打法参数化成可执行 SOP:变量表 + G0-G5 验证门 + P1-P29 权威索引 + 错误签名查表,下一批次照着敲即可。
「鸿蒙Flutter框架 0day适配实战」全系列 10 篇,本篇为第 5 篇(生产侧开篇):
| # | 篇目 | 侧 | 一句话主题 |
|---|---|---|---|
| 01 | 背景、分叉谱系、版本命名与 fvm fork 安装 | 消费 | 三层架构、三个接缝、七层工作量、路径 A、版本墙 |
| 02 | 手动 bootstrap tag 版本与三层核验 | 消费 | tag 探测、浅克隆、首次初始化、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 | 验证与真机验收 | 生产 | 三档引擎、设备侧单测、字体图标静默故障 |
配套仓库与文档:
- 上游 Flutter 仓库:github.com/flutter/flutter
- 鸿蒙分叉仓库(当前主线 3.47.8-ohos-1.0.0):atomgit.com/oh-flutter/flutter_flutter
- Flutter OH 环境搭建指导:OpenHarmony-flutter 环境搭建指导
- Skia 字体端口镜像(E7 恢复源):atomgit.com/CPF-Flutter/fluttertpc_skia
- Flutter 官方文档:docs.flutter.dev
- Dart 官方文档:dart.dev
总结
本篇用「3.44.9 → 3.47.4」这个真实批次,把生产侧的全貌讲完了一次:为什么要同步(版本墙 + 4 个月版本差)、同步的四个基线坐标、2263 文件适配集由什么构成(engine 826 / dev 633 / packages 421 为主体)、3.47 的 12 条 BC 适配档案(5 销项 / 2 挂真机 / 其余为决策与专项)、五阶段方案与 G1-G5 验证门、可直接执行的端到端 SOP 与 P1-P29 权威索引,以及开跑前的环境准备与三大风险。一句话总纲:同步不是搬代码,是清单驱动地重放一套适配集,每过一道门才进下一阶段。
下一篇(第 6 篇)进入 Phase 1+2 的实操细节:代理 HTTP/2 大包断裂的修障、浅克隆建基线、2263 文件清单恢复校验,以及 421 文件三方重打与「Dart SDK 必须从源码构建」这个本阶段最大发现。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- Flutter OH 环境搭建指导:OpenHarmony-flutter 环境搭建指导
- 分叉仓库(3.47 线,当前发布 3.47.8-ohos-1.0.0):atomgit.com/oh-flutter/flutter_flutter
- 上游 Flutter 仓库:github.com/flutter/flutter
- Flutter 官方文档:docs.flutter.dev
- Dart 官方文档:dart.dev
- 开源鸿蒙跨平台社区: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 环境搭建指导。
本文正文是 2026-09 3.44.9 → 3.47.4 同步批次的实录:其中的版本号、提交号与实测数字(适配清单文件数、构建边数、单测用例数、工件字节数等)都是那一批的现场值,不随上表更新;上表是当前可复现、可照做的环境组合。方法论、验证门与坑模型对 3.47.8 线同样适用。
更多推荐




所有评论(0)