RNOH 0.88.0-rc.1 适配教程:把 React Native 0.88.0-rc.1 带上 OpenHarmony

对象画像:这不是一个三方库,而是 RNOH 框架本身的版本升级适配——把 ohos_react_native 的 0.88 线从对齐上游 react-native 0.88.0-rc.0 推进到 0.88.0-rc.1,范围覆盖 JS 运行时、C++(ReactCommon)与 tester 宿主,最终在 HUAWEI nova 12 真机上跑通并把 5 个提交合入 oh-react-native/ohos_react_nativemain(MR !1,已合并)。

  • 适配分支:0.88-feature/rc.1(fork:uksri/ohos_react_native
  • MR:oh-react-native/ohos_react_native !1(2026-09-18 合并,merged_by jianguoxu
  • 执行时间:2026-09-17 → 2026-09-18;撰写时间:2026-09-18
  • 姊妹篇:《RNOH 0.88.0-rc.1 使用指南》(面向升级到 rc.1 的应用开发者)

证据分级声明(沿用系列约定):

  • 【记录】引自仓库既有文件 / 平台 API 响应 / 本次执行的真实命令输出,可复核到具体路径或命令;
  • 【代码】从仓库源码逐字读出,可 grep 验证;
  • 【复核】静态分析或推理得出的结论,尚未全部复验,单列于 §14,不当既成结论引用。

0. 前言

一句话画像:RNOH(React Native for OpenHarmony)是让 RN 应用跑在 OpenHarmony 上的框架层,本篇记录的是把它 从上游 react-native 0.88.0-rc.0 升级到 rc.1 的全过程——上游 rc.1 只改了 52 个文件,但要把这 52 个文件正确地"接"进 RNOH 的 monorepo(JS overlay + C++ vendor + 补丁体系),并在真机上完成验证与合入。

本篇产出:

产出状态
适配分支 0.88-feature/rc.1(基于 04797515c,5 个提交,全部带 DCO 签名)✅ 已推 uksri/ohos_react_native
MR !1 → oh-react-native/ohos_react_native:main(20 文件)✅ 2026-09-18 已合并
tester 真机验证(nova 12 / API 24 / arm64-v8a),版本徽标 RN 0.88.0-rc.1
PlatformConstantsTurboModule 单测✅ 12/12
新增适配文件 packages/react-native-harmony/setup-env.js(rc.1 新模块入口)✅ 已随 MR 合入
packages/react-native.patch 两处 rc.1 适配修复(写回补丁,保证 init-ws 可复现)✅ 已随 MR 合入

与系列里三方库文章的两点结构差异,先说清楚:

适配全流程总览

  1. 系列 §1 的"适配形态①②③④"是针对三方库的;框架升级适配不属于任何形态,本篇按"上游差异合入 + 构建体系排障"组织内容,章节号仍对齐系列模板(含 7′ 踩坑实录,故为 0–18 共 19 节)。
  2. 系列 §4 的 adaptation-check.py 校验的是三方库仓库结构,对框架 monorepo 不适用,本篇以等价自检替代(见 §4.4)。

1. 为什么做这次升级

【记录】RNOH 0.88 线(oh-react-native/ohos_react_nativemain)在 2026-09-16 停在对齐上游 0.88.0-rc.0(提交 04797515c,tag v0.88.0-rc.0)。上游随后发布 0.88.0-rc.1,npm 双版本可查:

$ npm view react-native@0.88.0-rc.0 version → 0.88.0-rc.0
$ npm view react-native@0.88.0-rc.1 version → 0.88.0-rc.1

rc.1 相对 rc.0 的增量规模(详见 §5):52 个文件(修改 49 + 新增 3、删除 0),集中在 featureflags 体系(C++/JS/Android 三份)、iOS SPM 构建脚本与版本元数据。工作量预估:

工作项预估实际
差异分析0.5h0.5h(npm 双包逐文件比对)
依赖与源码落位2h3h(pnpm 锁文件 + 子模块镜像 + vendor)
构建排障2h5h(九连坑,见 §7′)
真机验证1h2h(含发现版本上报缺陷并修复)
提交与 MR1h2h(平台 fork 规则踩坑,见 §12.4)

选这个目标的理由与系列"选库流程"同理:rc.1 已发布且无人做——oh-react-native/ohos_react_native 的 main 尚停在 rc.0,npm 侧 @react-native-oh/react-native-harmony 也未见 rc.1 产物(截至 2026-09-17 查询)。


2. 环境准备

环境搭建(DevEco Studio / OpenHarmony SDK / hdc / 签名 / RNOH_C_API_ARCH)请直接参考官方文档,不在此重写:

环境搭建请参考:RNOH 官方环境搭建

本篇的版本配套(实测通过的组合):

版本出处
React Native(上游)0.88.0-rc.1(npm 包)【记录】npm registry
React19.2.3【记录】pnpm-workspace.yaml overrides
RNOH 框架包@react-native-oh/react-native-harmony 0.88.0-rc.1(源码构建)【记录】packages/react-native-harmony/package.json
Node.js / pnpm22.x / 10.3.0packageManager 钉住)【记录】根 package.json
DevEco Studio / SDK26.x(D:\devs\DevEcoStudio,SDK API 26)【记录】本机
compatibleSdkVersion(tester)6.1.0(23),实机 API 24 可运行【记录】tester build-profile.json5
Metro0.83.7 锁定(沿用系列口径【记录】;本篇未复验 0.83.8+,见 §14)《RN三方库鸿蒙适配手把手教程.md》1.1

工作区来源:框架仓库 clone 到 短路径 C:\rnoh(为什么必须短路径,见 §7′ 坑⑤)。


3. 仓库从哪来(过程,必配 3 图)

3.1 先分清三条"上游"(过程图 1)

框架在这个生态里有三条容易混淆的线,动手前必须分清:

仓库来源与两条版本线

  • atomgit.com/oh-react-native/ohos_react_native(0.88 线)main = 04797515c,即本次适配的基点(tag v0.88.0-rc.0)。注意它本身是 canonical 仓库 CPF-RN/ohos_react_native 的一个 fork,0.88 的适配工作在这条 fork 线上推进;
  • gitcode.com/CPF-RN/ohos_react_native(canonical):fork 网络的根项目,main 停在 0.86 线1750e94fd)——MR 评审与合入的网络根,见 §12.4;
  • 上游 npm 包 react-native:rc.0 / rc.1 两个 tarball 是差异分析的权威依据(§5)。

另外有 7 个 C++ 子模块(boost / folly / fmt / glog / double-conversion / fast_float / hermes)钉在 .gitmodules,直连 GitHub 在本机不可达,经镜像代理(https://gh-proxy.com/https://github.com/...)按 gitlink 钉住的 commit 逐个拉取——必须钉在 superproject 记录的 commit 上,浮动到分支头会在 §7′ 坑⑥⑦ 爆雷。注意嵌套子模块:libs/numeric/ 下还有 conversion / interval / odeint / ublas 四个二级 gitlink,git ls-tree HEAD:libs 只列一级,要用 git ls-tree -r HEAD libs 数全(共 149 个 gitlink)。

3.2 clone 到宿主机,并解开浅克隆(过程图 2)

git clone -b main https://atomgit.com/oh-react-native/ohos_react_native.git
# 若用了 --depth 1(本工作台最初就是),必须解浅:
git fetch --unshallow

浅克隆演示与解浅后的状态

浅克隆在这里有两个具体危害:① 系列模板 §3.2 说的 diff 证据拿不到;② 推送被拒——AtomGit 服务端拒绝 shallow update(! [remote rejected] ... (shallow update not allowed)),提交了也推不出去。解浅后 git rev-list --count HEAD = 5860(5858 历史 + 本适配提交后的状态)。

3.3 建分支与目录结构(过程图 3)

分支名沿用系列约定 feat/ohos_<名>_<版本> 的框架变体:0.88-feature/rc.1(对齐 RNOH 社区《仓库分支管理规范》的 ${version}-feature/<name>,规范同时禁止直推 main / *-main / *-stable)。

适配分支与 5 个提交、monorepo 结构

monorepo 关键目录与本次适配的接触面:

目录作用本适配是否触碰
packages/react-native上游 react-native 子模块(gitlink 指向 facebook/react-native)版本推进时由 npm 包替代其内容(§6.1)
packages/react-native-harmonyJS overlayLibraries/src/delegates/types/ 为 gitignore 的生成物)✅ 同步 rc.1 内容 + 新增 setup-env.js
packages/react-native.patch对上游源码的 128 处改动(delegates 化、Harmony 化),init-ws 时应用✅ 两处 rc.1 修复写回(§7′ 坑⑧⑨)
packages/tester/harmonytester 宿主(可安装到真机的样例 App),内嵌 react_native_openharmony(框架源码模块)✅ 版本串 / 徽标 / 版本常量
packages/react-native-harmony-cli / -hvigor-pluginRNOH CLI 与 hvigor 插件✅ 版本号与 tgz 重建

4. 适配结构补全

4.1 如实说明:框架没有"脚手架命令",只有一套生成机制

三方库适配可以手写 11 个文件;框架的正道是复用仓库自带的生成机制,顺序如下(全部是仓库既有脚本,非本篇新造):

  1. pnpm install——安装 workspace 依赖,tester 的 postinstall 会从 build-profile.template.json5 生成 build-profile.json5
  2. pnpm init-wsgit submodule update --init --recursive + pnpm i + pnpm run _integrate-upstream-code + 重建 hvigor 插件 tgz + 递归 setup
  3. _integrate-upstream-codescripts/integrate-upstream-code.ts)就是框架版的"脚手架":给 packages/react-native 子模块打 react-native.patch,然后把 delegates / Libraries / src / types_DEPRECATED(→types) 同步进 overlay 包,把 ReactCommon vendor 到 cpp/third-party/rn/ReactCommon

本篇因 GitHub 子模块不可达(§3.1),用 npm rc.1 包替代子模块内容复刻了这一机制,见 §6。

4.2 overlay 的"生成物"属性必须先搞清楚

packages/react-native-harmony/.gitignore 明确写着:Libraries/*types/*src/*delegates/* 都是 # To add a new file to one of those directories, use 'git add -f'生成目录(仅 Libraries/RegisterPageName/src/private 的测试/文档白名单例外)。这意味着:

  • 全新 clone 的仓库不能直接构建——overlay 是空的(首跑 bundle 即报 Unable to resolve module ./Libraries/Core/InitializeCore,见 §7′ 坑①);
  • 任何"源码修复"如果只落在生成目录里,等于没有交付——必须写回 react-native.patch 或提交为包根的正式文件(§7′ 坑⑧⑨ 的处理原则)。

4.3 本适配需要落位的清单(逐项列路径)

#路径性质说明
1cpp/third-party/rn/ReactCommon/**1452 个文件生成物(gitignore)rc.1 npm 包 ReactCommon/ + react-native.patch 的 ReactCommon 段(128 段中的 50 个既有文件改动 + 若干新增)
2overlay Libraries/src/delegates/types/生成物(gitignore)rc.1 npm 包对应目录 + 补丁(types_DEPRECATED → types,脚本注释明示 0.88 起上游改名、RNOH 保留自身目录名)
3packages/react-native-harmony/setup-env.js(18 行)正式提交rc.1 新增 react-native/setup-env 出口;RNOH 解析器会把该请求重定向到包根,缺失即 bundle 失败(§7′ 坑②)。与包根 index.js / ts.ts / ets.ets 同类,随 files 通配发布
4packages/react-native.patch(128 段中改 2 段)正式提交jserrorhandler 破环 + RawPropsKey.h 守卫(§7′ 坑⑧⑨),修复必须写回补丁才能让全新 init-ws 复现
5版本号 ×12(package.json 等)+ pnpm-lock.yaml / oh-package-lock.json5正式提交见 §8

4.4 结构自检(等价 adaptation-check.py

adaptation-check.py 面向三方库仓库,对 monorepo 不适用。本篇用三个等价命令自检(全部可复跑):

# ① 全量补丁能否干净应用于"纯 rc.1 树"(最硬的一条):期望零输出
cd <干净 rc.1 解包目录> && git apply -p3 --check ../ohos_react_native/packages/react-native.patch
# ② 生成目录就位核对:ReactCommon 文件数应为 1452
find packages/tester/harmony/react_native_openharmony/src/main/cpp/third-party/rn/ReactCommon -type f | wc -l
# ③ overlay 关键入口就位
ls packages/react-native-harmony/Libraries/Core/InitializeCore.js packages/react-native-harmony/setup-env.js

①在修复写回补丁后复验通过(0 报错),且补丁应用后的 ReactCommon/jserrorhandler/CMakeLists.txtReactCommon/react/renderer/core/RawProps.cpp 与工作台 vendored 文件 逐字节一致cmp 校验)。

4.5 "零改动证据"的框架版

系列模板要求证明"不改上游接口"。框架版的等价命题是:除声明的适配点外,不额外改动上游源码。证据:

  • 上游 rc.1 npm 树 + react-native.patch 全量应用 --check 通过,即补丁外的上游文件与官方发布逐字节一致
  • 本适配对"上游内容"的增量只有两类:① setup-env.js(包根新增入口,不修改任何上游文件);② patch 内 2 段修复(每一处都在 §7′ 有"现象→根因→修复"记录);
  • Libraries/src/ 等生成目录与 rc.1 + patch 的产物一致,未手工增删。

5. 上游差异分析:rc.0 → rc.1 到底改了什么

方法:从 npmmirror 下载 react-native-0.88.0-rc.0.tgzrc.1.tgz,逐文件 diff -qr(比 GitHub 可靠——本机 GitHub 直连不可达,且 npm 包即发布事实)。

rc.0 → rc.1 差异统计

52 个文件的分布与落点

合计 52 = 修改 49 + 新增 3、删除 0。按"对鸿蒙适配的落点"归类:

落点文件数内容处理
JS 运行时(进 bundle)11Libraries/ 4(ReactFabric 三实现 + 版本号)、src/ 6(featureflags、webapis、react-private-interface)、package.json 1(新增 ./setup-env exports)react-native@0.88.0-rc.1 npm 依赖 + overlay 同步自动带入
C++(vendor 进 .so)11ReactCommon/react/featureflags/ 8、react/nativemodule/featureflags/ 2、cxxreact/ReactNativeVersion.h 1vendor 同步(§4.3#1),版本头实测 Prerelease = "rc.1"
类型2types_generated/(新增 FabricUIManager.d.tsreact-private-interface.d.ts随 overlay types/ 同步
Android 专属11ReactAndroid/**(featureflags Kotlin/JNI、版本号)❌ 鸿蒙无此层,不适用
iOS/Apple 构建脚本14scripts/spm/**(新增 ios-deployment-target.jsswiftpm-config.js)+ codegen/setup 脚本❌ 不适用(鸿蒙走 hvigor/CMake)
iOS ObjC / 共享头2React/Base/RCTVersion.mFBReactNativeSpecJSI.hRCTVersion 不适用;JSI 头随 vendor 生效
版本元数据1sdks/hermes-engine/version.properties记录项(Hermes 为预编译 .so)

结论:鸿蒙侧真正要"跟"的是 JS 11 + ReactCommon 11 + 类型 2 + 元数据 1;两个功能性变化点是 rc.1 的 featureflags 扩展与 react-native/setup-env 新模块,后者直接导致一处适配新增(§7′ 坑②)。


6. 架构决策

6.1 为什么"npm 包 + 补丁"而不是"更新子模块"

init-ws 的正规路径要求能克隆 facebook/react-native 子模块(GitHub)。本机 GitHub 直连不可达,而 rc.1 的 npm 包内容 = 官方仓库 packages/react-native/ 的发布物(monorepo 布局,ReactCommonpackages/react-native/ 下)。因此:以 npm rc.1 tarball 展开 → git init 提交为基线 → git apply -p3 应用补丁(补丁路径前缀为 packages/react-native/-p3 恰好剥掉三层)→ 按同步脚本的同款目录映射拷入。验证手段:git apply --check 于纯 rc.1 树零报错。

6.2 修复写回补丁,而不是只改生成目录

rc.1 引入的两处构建阻塞(§7′ 坑⑧⑨)的修复点都在"生成目录"(vendored ReactCommon)里。若只改生成目录:git status 干净、看似无事,但任何一次 init-ws 重新生成就会复现故障。因此修复以 diff 形式写回 packages/react-native.patch(在干净 rc.1 基线仓库里重新生成这两个文件段的 hunk 并拼接),再用"全新树 + 全量补丁 + cmp 逐字节比对 vendored 文件"闭环验证。

6.3 版本上报链路的最小改动原则

真机验证暴露的版本号问题(§11.3)涉及三层:JS bundle 的 ReactNativeVersion(rc.1,自动带入)→ ArkTS 侧常量(RNInstancesCoordinator.ets:245 硬编码,改为 rc.1)→ 下发 JS 的 Platform.constants.reactNativeVersionPlatformConstantsTurboModule)。修复遵循最小面:ArkTS 常量只改值;TurboModule 按上游契约补 prerelease(§7 对账表),不改调用方。


7. 接口/字段逐一对账

7.1 上游 52 文件 → RNOH 落点对账

见 §5 表格(逐文件 → 落点 → 处理),此处不重复。要点:49 处修改里没有一处落在 RNOH 的 ArkTS/补丁层,即 rc.1 没有动 RNOH 补丁所依赖的上游结构——这是补丁能零冲突应用的根本原因(git apply --check 证实)。

7.2 Platform.constants.reactNativeVersion 契约对账(本篇新增的行为对齐)

真机验证发现徽标只显示 RN 0.88.0-rc.1 的前缀形式(详见 §11.3),排查发现 RNOH 实现与上游契约有偏差:

上游契约(0.88.0-rc.1)【代码】RNOH 修复前修复后
类型声明Libraries/Utilities/Platform.d.ts{major: number; minor: number; patch: number; prerelease?: string | null | undefined}
patchnumber字符串 '0-rc'split('.', 3)-rc 卷进第三段)0(数字)
prerelease可选字段,上游 Android AndroidInfoHelpers.kt:88major.minor.patch[-prerelease] 拼接缺失'rc.1'
RN 自身版本检查ReactNativeVersionCheck.js 只比较 major/minor,格式化同样拼 -prerelease不受影响不受影响

修复位置【代码】:PlatformConstantsTurboModule.ts:18ReactNativeVersionInfo 接口)、:30parseReactNativeVersion(),按 - 拆 prerelease、三段转数字、缺失/非数字回退 0)、:67(调用点)。调用链上游:RNInstancesCoordinator.ets:245 的版本常量由 '0.88.0-rc.0' 修正为 '0.88.0-rc.1'(该值经 RNOHCoreContext 下发给 TurboModule)。


7′. 构建踩坑实录(九连坑)

以下全部为本次适配实际发生的阻塞,按时间序。每条按「现象 → 根因 → 修复 → 验证」。先上全景图:

构建链路与九个阻塞点

坑① overlay 是空的:Unable to resolve module ./Libraries/Core/InitializeCore

  • 现象:首次 react-native bundle-harmonyUnable to resolve module ./Libraries/Core/InitializeCore from ...\react-native-harmony\index.js
  • 根因:overlay 的 Libraries/*src/* 等是 init-ws 生成物(§4.2),全新 clone 为空,index.js 的 require 自然断链。
  • 修复:按 integrate-upstream-code.ts 的目录映射,把"rc.1 + 全量补丁"的 Libraries/ src/ delegates/ types_DEPRECATED→types 拷入 overlay。
  • 验证:bundle 进入下一阶段(报出新的、更深的错误 = 前一关已过)。

坑② react-native/setup-env 解析失败(rc.1 新增模块)

  • 现象Unable to resolve module react-native/setup-env from ...\ReactFabric-prod.js(rc.1 的 ReactFabric 新增该 require)。
  • 根因:RNOH 的 metro 解析器把 react-native/* 请求重定向到 overlay 包根;rc.1 的 package.json exports 新增 ./setup-env,而 overlay 根没有对应文件。
  • 修复:新增包根 setup-env.js(18 行),内容与上游 src/setup-env.js 等价、指向 overlay 内同步而来的 src/private/setup/setUpDefaultReactNativeEnvironment;作为正式提交交付(§4.3#3)。
  • 验证:bundle 生成成功(bundle.harmony.js,2,308,166 字节)。

坑③ hvigor 依赖自举被 pnpm 拦截:ERR_PNPM_IGNORED_BUILDS

  • 现象:hvigor 配置阶段执行的 pnpm installIgnored build scripts: agent-browser / canvas / esbuild 后失败。
  • 根因:hvigor wrapper(~/.hvigor/wrapper/tools/10.28.2)自带 pnpm,默认拒绝未白名单的构建脚本。
  • 修复:wrapper 目录 package.jsonpnpm.onlyBuiltDependencies 白名单(本机环境处理,不入库)。
  • 验证:配置阶段继续推进;后续又报 Cannot find module '@rnoh/hvigor-plugin',按系列先例在 hvigor-config.json5'hvigor.dependency.useNpm': true 解决(该属性为本机环境项,未随 MR 提交)。

坑④ 路径长度超限:The length of path exceeds the maximum length: 259

  • 现象:hvigor 报 00306001 Specification Limit Violation
  • 根因:工作区在 Desktop\tm\rn088\ohos_react_native,深度路径 + 嵌套生成目录超 259 字符限制。
  • 修复:工作区整体迁至 C:\rnoh。注意 Junction 无效——hvigor 会把路径规范化回真实长路径,必须物理短路径(robocopy 复制后修复子模块 gitdir 引用)。
  • 验证:同一条 cmake 命令不再报限长。

坑⑤ include could not find requested file: BoostRoot

  • 现象:entry 的 CMake 配置报 boost/CMakeLists.txt:20 (include): BoostRoot 缺失。
  • 根因:boost superproject 的 CMakeLists.txt:20 依赖 tools/cmake 子模块BoostRoot.cmake 所在),而该子模块从未拉取。
  • 修复:按 gitlink(69f16e28)经镜像补拉 tools/cmake
  • 验证:该错误消失,配置推进到编译期。

坑⑥ Target "boost_date_time" links to: Boost::numeric_conversion but the target was not found

  • 现象:CMake generate 阶段报 date_time / lexical_cast 引用了不存在的 Boost::numeric_conversion
  • 根因BoostRoot.cmake 会做依赖闭包扫描——locale → thread → date_time → numeric_conversion;而 numeric_conversion 位于 libs/numeric/conversion(嵌套 gitlink)。一级 git ls-tree HEAD:libs 只有 145 个 gitlink,递归共 149 个,嵌套的 4 个(numeric/conversion、interval、odeint、ublas)未拉取。闭包里"应该有"的 target 因子模块缺失而真缺,字母序先处理的 date_time 便报 target 未找到。
  • 修复:递归补齐 4 个嵌套子模块。其中 numeric_conversiongitlink 名带下划线(仓库 boostorg/numeric_conversion),按连字符仓库名拉取会 404/not our ref;同时对不存在的对象哈希做浅拉取会被 GitHub 拒绝,改用完整仓库浅 fetch 解决。
  • 验证git ls-tree -r HEAD libs | awk '$1=="160000"' | wc -l = 149,全部检出在钉住 commit;CMake generate 通过。

坑⑦ CMake 目标环:react_cxxreact ↔ jserrorhandler(rc.1 引入)

  • 现象The inter-target dependency graph contains the following strongly connected component (cycle): react_cxxreact ↔ jserrorhandler ... Cyclic dependencies are allowed only among static libraries.(两者都是 OBJECT 库)。
  • 根因:rc.1 起上游 react_cxxreact 新增链接 jserrorhandler;而 RNOH 补丁让 jserrorhandler 反向链接 react_cxxreact(为取 <cxxreact/ErrorUtils.h> 头)。rc.0 时代单向不成环,rc.1 成环。
  • 修复:jserrorhandler 侧只需要头文件——把链接依赖改为 target_include_directories(jserrorhandler PRIVATE ${REACT_COMMON_DIR}/cxxreact)修复写回 react-native.patch(§6.2)。
  • 验证:CMake generate 通过;全新 rc.1 树全量补丁 --check 通过且与 vendored 文件逐字节一致。

坑⑧ RawPropsKey.h 不存在(补丁引用了上游没有的头)

  • 现象RawProps.cpp:12:10: fatal error: 'react/renderer/core/RawPropsKey.h' file not found
  • 根因:补丁给 RawProps.cpp 增加了 #include <react/renderer/core/RawPropsKey.h>,但该头在上游 0.88 的 rc.0 与 rc.1 中都不存在(以 GitHub rc.0/rc.1 tag 的 git ls-tree 核实,npm 包同样没有)。它只服务于补丁的 PARALLELIZATION_ON 并行化分支。
  • 修复:把该 include 收进同一个 #ifdef PARALLELIZATION_ON 守卫(本构建未开并行化,语义不变),写回补丁。
  • 验证:编译越过该文件;后续唯一编译错误是坑⑨。

坑⑨ boost 线程原语报错:pthread_setcancelstate 未声明

  • 现象boost/core/detail/sp_thread_sleep.hpp:73:5: error: use of undeclared identifier 'pthread_setcancelstate'
  • 根因:漏了 packages/boost.patch——init-ws 机制要求把它打到 boost 子模块上(补丁内容即 OHOS musl 的 pthread 兼容层),手动拉子模块的流程里漏了这一步。
  • 修复git apply packages/boost.patch 于 boost 子模块根。
  • 验证:错误消失;随后 BUILD SUCCESSFUL(50 任务,增量 3m21s)。

速查表

#阶段症状关键词一句话修法是否入库
bundleInitializeCore 解析失败跑 overlay 同步(init-ws 机制)否(生成物)
bundlereact-native/setup-env 解析失败overlay 包根补 setup-env.js
hvigorERR_PNPM_IGNORED_BUILDS / 找不到 hvigor-pluginwrapper 白名单;hvigor.dependency.useNpm否(本机)
hvigor/cmake路径超 259工作区挪短路径(Junction 无效)否(本机)
cmake找不到 BoostRoottools/cmake 子模块否(子模块)
cmakeBoost::numeric_conversion 未找到补齐嵌套 libs/numeric/*(下划线仓库名)否(子模块)
cmakereact_cxxreact ↔ jserrorhandler 目标环补丁改为仅注入 include 路径✅(patch)
编译RawPropsKey.h not foundinclude 收进 PARALLELIZATION_ON 守卫✅(patch)
编译pthread_setcancelstate 未声明应用 packages/boost.patch否(子模块补丁)

8. 版本号与依赖提升

提升清单(0.88.0-rc.00.88.0-rc.1,共 12 个文件)【记录】:

文件提升内容
package.json(pnpm.overrides)+ packages/react-native-harmony / -cli / -hvigor-plugin(含 lock)/ -sample-package / template/template / testerpackage.jsonversionreact-native@react-native/* 依赖
packages/tester/harmony/hvigor/hvigor-config.json5插件 tgz 文件名 rnoh-hvigor-plugin-0.88.0-rc.1.tgz
packages/tester/harmony/react_native_openharmony/oh-package.json5 + build-profile.json5version-DVERSION_STRING="0.88.0-rc.1"(release 档)
packages/tester/harmony/oh-package-lock.json5ohpm 锁定
pnpm-lock.yaml全量解析(190 处 rc.1 引用,0 处 rc.0 残留)
RNInstancesCoordinator.ets:245ArkTS 下发 JS 的版本常量(§7.2)

三个坑:

  1. minimumReleaseAge: 4320(pnpm-workspace.yaml,“发布满 3 天才可安装”)会静默跳过刚发布的 rc.1、继续装 rc.0——安装时不报错,bundle 阶段才炸。临时置 0 安装后恢复原值(该配置是上游供应链保护,不应顺手删除)。
  2. pnpm-lock.yaml 的两万行 diff 是假象:pnpm 10 写单引号、仓库基线是双引号。归一引号后真实差异只剩 rc.1 解析与 peer 哈希;用 pnpm install --frozen-lockfile 验证锁文件与 package.json 一致(通过)。
  3. hvigor 插件 tgz 必须重建pnpm run _recreate-hvigor-plugin 产出 rnoh-hvigor-plugin-0.88.0-rc.1.tgz,否则 hvigor-config.json5 引用断链。

9. 交付文件说明(与三方库模板的差异)

框架仓库已自带系列模板要求的多数交付物,本适配的交付重心因此不同:

系列模板要求本仓库现状本适配动作
README.OpenHarmony.md / _CN.md(七节)✅ 仓库既有(0.88 线随 rc.0 已带)未改
README.OpenSource(7 字段)✅ 仓库既有未改
spec.json / 代码检查报告 / 契约测试tester 自带测试体系补充单测用例(§10)
.har 预构建仓库以源码分发;官方 har 走发布流程不提交构建产物(遵循仓库 .gitignore
react-native.patch(框架特有)128 段✅ 2 段修复(本适配的核心交付)
setup-env.js(rc.1 新增入口)✅ 新增 18 行
CHANGELOG.md / release-notes维护者发布流程未代写;维护者合并后已补 664709a7e docs: add 0.88.0-rc.1 release notes

10. 验证

10.1 单元测试(12/12)

PlatformConstantsTurboModule.test.ts 更新:新增 reports the prerelease separately from patch0.88.0-rc.1{major:0, minor:88, patch:0, prerelease:'rc.1'}),并把原先固化 split('.', 3) 旧行为的两个用例改为断言新契约(非数字段回退 0;仍只取前三段)。

PlatformConstantsTurboModule 单测 12/12

10.2 产物级证据

  • bundle(2,308,166 字节)内含 prerelease='rc.1'grep -ao 实测);
  • vendored ReactCommon/cxxreact/ReactNativeVersion.hPrerelease = "rc.1"
  • ArkTS 字节码(ets/modules.abc)含 0.88.0-rc.1libhermestooling.so0.88.0-rc.1 字符串。
  • ⚠️ 如实记录:debug 构建(entry 驱动)下 librnoh_core.soRNOH_LIB_VERSION= 标记串为——entry/build-profile.json5 的 cmake arguments 未传 VERSION_STRING,CMake 从 oh-package.json5 推导的值在该链路为空(build.ninja 实测 -DVERSION_STRING=\"\")。仅影响 strings 类诊断标记,不影响任何运行行为;修复建议见 §14。

10.3 真机记录

设备HUAWEI nova 12(BLK-AL00)
系统HarmonyOS 6.1.0.135(SP8C00E120R2P6),API 24,arm64-v8a
安装包entry-default-signed.hap(50,037,089 字节,debug 档,调试签名)
启动aa start -b <bundleName> -a EntryAbility 正常;hilog 可见 MountingManagerCAPI.cpp:210> Mutation (type:INSERT ...) 连续 Fabric 挂载【记录】
交互uitest uiInput click 进入 AccessibilityInfo 测试页:11 个测试项渲染、按钮可点、‹ Back 可返回

真机主页:版本徽标 RN 0.88.0-rc.1

真机组件测试页(AccessibilityInfo)


11. Demo:tester 在真机跑起来

tester 是仓库自带的宿主(等价三方库文章里的"宿主工程"),步骤:

  1. 生成内嵌 bundle(tester 从 rawfile 加载 bundle.harmony.js,不依赖 metro 常驻):
    cd packages/tester && RNOH_TESTER_ONLY__TARGET_PLATFORM=harmony npx react-native bundle-harmony --dev=false --minify=true
  2. 构建hvigorw --mode module -p module=entry@default -p product=default -p buildMode=debug assembleHap(本机构建脚本固定 DEVECO_SDK_HOME 与 DevEco 自带 node/ohpm 的 PATH)。
  3. 签名与设备三件套(系列已知坑,本篇全部再踩一遍,方案沿用):调试 profile 必须含本机 UDID(发布档会报 no signature file);hdc install 要装 -signed.hapabiFilters 要含 arm64-v8a(模拟器是 x86_64)。另有一坑:签名档绑定的 bundleName 必须与 AppScope/app.json5 一致,否则报 bundleName ... does not match the bundleName in the generated SigningConfigs(本机以调试档对应 bundleName 本地化解,该改动不入库)。
  4. 安装与启动hdc install -r ...entry-default-signed.hapaa start

11.3 真机暴露的版本上报缺陷(本篇最有价值的发现)

首装后徽标显示 RN 0.88.0-rc 而非 rc.1。排查链:徽标(Navigation.tsx:173)→ Platform.constants.reactNativeVersion(TurboModule)→ ArkTS 常量(RNInstancesCoordinator.ets:245)。发现两个独立问题

  1. 常量硬编码 '0.88.0-rc.0' 未随升级修改(§7.2,已修复——这也验证了系列教训:版本提升时 --include 扫描必须覆盖 .ets/.ts 源码,不能只扫 json/yaml);
  2. TurboModule 用 split('.', 3) 解析,0.88.0-rc.1 被截成 patch:'0-rc'prerelease 丢失——rc.0 与 rc.1 的显示完全相同,与上游契约(§7.2 对账表)不符。

修复(契约对齐 + 徽标按上游 ReactNativeVersionCheck 格式化)后重装,徽标显示 RN 0.88.0-rc.1(见 §10.3 截图),单测 12/12。两处修复即 MR 的第 4、5 个提交。


12. 提交与发布

12.1 提交内容甄别

处理内容
✅ 提交§8 版本提升 15 文件、react-native.patch 2 段修复、setup-env.jsRNInstancesCoordinator.ets 常量、README 版本声明、单测更新
❌ 不提交本机环境项:hvigor useNpm、调试签名的 signingConfigs、本地 bundleNameabiFilters、CRLF 噪声(oh-package.json5 等 2 处还原)、robocopy 误删的 8 个跟踪文件(先还原)
🚫 绝不提交构建产物(.cxx/build/oh_modules)、token、签名材料

12.2 提交结构(5 个,Conventional Commits + Signed-off-by

9c1bd1e2 chore(Upgrade) 版本提升(含 ArkTS 常量与 README)→ 214d0692 fix(CMake) 两处构建阻塞 → 32916232 feat(Config) setup-env → fa971a52 fix(TurboModules) prerelease 契约 → 75fa3f87 fix(Examples) tester 徽标。commitlint 本地通过(subject 英文、body 含影响范围、DCO 签名)。

12.3 推送坑:浅克隆被服务端拒绝

git pushshallow update not allowed——工作台是 depth 1 克隆。git fetch --unshallow(补全 5858 个历史提交)后推送成功。推框架仓库前先确认非浅克隆git rev-parse --is-shallow-repository)。

12.4 MR 坑:兄弟 fork 之间不能互发 MR

目标仓库 oh-react-native/ohos_react_nativeCPF-RN/ohos_react_nativefork(0.88 线所在地),用户自己的 uksri/ohos_react_native 也是 CPF-RN 的 fork——兄弟 fork 之间无法建 MR(平台一律路由到 fork 网络根项目,导致 base 变成 0.86 线的 main、diff 膨胀到 124 文件;本篇先后误建 #3491/#3492/#3493 并全部关闭)。正确做法:fork 一份目标仓库本身作为载体(uksri/ohos_react_native-rc1,父仓库恰为目标),推送唯一命名分支(0.88-feature/rc1-org,避免与旧 fork 同名分支歧义),再以 head = uksri/ohos_react_native-rc1:0.88-feature/rc1-org 的完整写法调平台 API 建 MR——MR !1 应声而生,20 个文件

12.5 结果

  • MR !1 于 2026-09-18 06:46(UTC+8)被 jianguoxu 合并【记录:GitCode API state: merged / merged_by]:

MR !1 状态核对(API 输出:merged)

  • 维护者随后在 main 顺次追加 664709a7e docs: add 0.88.0-rc.1 release notes 等 3 个文档提交;
  • 遗留:仓库当前无 0.88-main/0.88-feature 线性分支,0.88 线的后续合入方式以维护者安排为准(见 §14)。

13. FAQ(现象 → 根因 → 修复 → 验证)

Q1:真机上版本徽标只显示 RN 0.88.0-rc,看不到 rc 序号?
现象如题。根因有二:ArkTS 版本常量漏升(RNInstancesCoordinator.ets:245)+ PlatformConstantsTurboModulesplit('.', 3) 截断且 tester 徽标只渲染三段数字。修复:常量对齐 rc.1;TurboModule 按上游契约输出 patch: number + prerelease;徽标按上游 ReactNativeVersionCheck 格式化。验证:真机徽标 RN 0.88.0-rc.1,单测 12/12。(来源:本篇 §11.3)

Q2:pnpm install 后 bundle 仍按 rc.0 解析?
现象:依赖已写 rc.1,安装不报错但产物是 rc.0。根因:minimumReleaseAge: 4320 让 pnpm 跳过"发布未满 3 天"的 rc.1。修复:临时 minimumReleaseAge: 0 安装后恢复。验证:grep -c '0.88.0-rc.0' pnpm-lock.yaml = 0。(来源:§8)

Q3:hvigor/cmake 报"路径超过 259"?
根因:深层工作区。修复:物理迁移到短路径(如 C:\rnoh);Junction 无效(hvigor 会规范化回真实路径)。验证:原命令不再报 00306001。(来源:坑④)

Q4:CMake 报 Boost 相关 target/文件找不到?
两个子坑:BoostRoot 缺 → 没拉 tools/cmake 子模块;Boost::numeric_conversion 缺 → 没拉嵌套 libs/numeric/*(注意仓库名 numeric_conversion 带下划线)。修复:按 git ls-tree -r 补齐全部 149 个 gitlink 并钉住 commit。验证:git am/构建通过。(来源:坑⑤⑥)

Q5:全新检出按 init-ws 构建,rc.1 还是构建失败?
若 MR 未合入会复现坑⑦⑧——两处修复已写回 packages/react-native.patch合入后不存在此问题;若从旧基线操作,应用本篇 §4.3 的补丁或 git am 补丁系列。(来源:§6.2)

Q6:给 oh-react-native/ohos_react_native 提 MR 被路由到 CPF-RN
根因:两者是 fork 网络,平台只允许 fork → 根项目的 MR。修复:fork 目标仓库为载体 + headowner/repo:branch 完整写法。验证:MR base 显示目标仓库、文件数符合预期。(来源:§12.4)


14. 复核发现(未全部复验,单列)

#状态
1debug 构建 librnoh_core.soRNOH_LIB_VERSION= 标记为空(entry 未传 VERSION_STRING,CMake 推导链路为空)已定位(build.ninja 实测),未修复;仅影响诊断标记
2compatibleSdkVersion 6.1.0(23) 下仅在 API 24 实机验证,未在 API 23 设备验证未验证
3Release / debugOptimized 档构建与 har 产物安装未验证(本篇仅 debug HAP)
4Metro 锁 0.83.7 的口径在 0.88 线是否仍成立沿用【记录】,未复验
5canonical CPF-RN main 仍为 0.86 线,0.88 线合入节奏与 0.88-* 分支规划待维护者
6docs/Samples/** 的示例工程仍钉 rc.0(上游 rc.0 发布提交亦未动它们)待维护者
7本机 pre-push 钩子 verify 的两类既有失败(CHANGE_INFO 未注入导致 cpp-formatting 必失败;tester typecheck 130 个既有错误,含 Navigation.tsx 一处经还原对照确认的既有报错)与本适配无关,已如实标注

15. 成果与沉淀

产出状态备注
0.88.0-rc.1 适配(5 提交 / 20 文件)✅ 已合入 oh-react-native/ohos_react_native:main(MR !1,merged 2026-09-18)含维护者后续 release-notes 提交
真机可运行 tester(徽标 RN 0.88.0-rc.1✅ nova 12 实测截图见 §10.3
PlatformConstants 契约对齐 + 单测✅ 12/12对上游类型与 Android/iOS 实现三重对账
react-native.patch rc.1 兼容(2 处)干净 rc.1 树 --check 通过 + 逐字节比对
九连坑方法论✅ 本篇 §7′子模块钉 commit / 嵌套 gitlink / 补丁写回原则可复用
补丁系列(git format-patch 5 个)✅ 已存工作台 rn088/pr-patches/干净基点套用验证通过
载体 fork uksri/ohos_react_native-rc1✅(MR 合并后可删)兄弟 fork 限制的过渡产物

16. checklist(可复用给"框架版本升级适配")

代码侧

  • 上游 delta 用 npm 双 tarball 逐文件比对(不凭 release notes)
  • 每个 delta 文件标落点:JS / C++ / 类型 / 平台不适用
  • 子模块按 gitlink 钉 commit(含嵌套 gitlink,ls-tree -r 数全)
  • 平台专属补丁(如 boost.patch)确认已应用
  • 源码修复写回 patch,并在"干净上游树 + 全量补丁"上 --check + 逐字节比对
  • 版本号提升覆盖 全部形态:package.json / oh-package / hvigor tgz / build-profile 版本串 / ArkTS 硬编码常量
  • 行为对齐以上游类型 + 上游双端实现 + RN 自身消费代码三重对账

交付侧

  • Conventional Commits + DCO;subject 英文、body 含影响范围
  • 提交甄别:本机环境项 / CRLF 噪声 / 构建产物一律不进
  • 非 shallow 仓库再推送(服务端拒 shallow update)
  • MR 目标仓库与 fork 关系先查清(兄弟 fork 需载体 fork + owner/repo:branch
  • 真机记录:设备型号 / API / ABI / 安装包字节数 / 启动与交互 / 截图
  • 未复验项如实单列(§14)

17. 参考

  • 上游:react-native@0.88.0-rc.1(npm)、facebook/react-native tag v0.88.0-rc.1
  • 本适配仓库:oh-react-native/ohos_react_native(0.88 线)、MR !1
  • fork:uksri/ohos_react_native(分支 0.88-feature/rc.1)、载体 uksri/ohos_react_native-rc1
  • 环境文档:RNOH 官方环境搭建
  • 系列规范:三方库技术文章 README;姊妹篇:RNOH 0.88.0-rc.1 使用指南
  • 同系列对照:react-native-screenshot-aware(构建四连坑)、react-native-video-duration(真机四连坑)——本篇的"九连坑"是构建期+真机期的合流
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐