- OpenHarmony
- 移动开发
- 跨平台
【免费下载链接】ohos_react_native
React Native鸿蒙化仓库
本文基于 ohos_react_native(React Native 鸿蒙化仓库,简称 RNOH)中的实验特性说明文档 packages/react-native-harmony/scripts/hermesv1.md,完整讲解 Hermes V1 引擎的启用流程。文章将覆盖:Hermes V1 二进制源码构建(仅 macOS)、
hermes-compiler覆盖安装、Hermes V1 字节码打包、原生侧 CMake 开关配置,以及构建日志、objdump字节码版本与运行时属性三层验证手段,并结合仓库源码(build-hermes.sh、hermesv1_cmakelists.patch、bundle-harmony.ts、各CMakeLists.txt)逐层解释其底层原理。
一、Hermes V1 是什么:实验特性与适用前提
在 React Native 鸿蒙化体系中,Hermes 是默认的 JavaScript 引擎(见 packages/react-native-harmony/scripts/resources/react-native-harmony.cmake 中if(USE_HERMES) ... target_link_libraries(... hermesvm ...)的默认分支)。而Hermes V1是仓库提供的一套独立于社区主线的 Hermes 引擎变体:它从 Facebook Hermes 仓库的特定稳定分支250829098.0.0-stable检出并固定到提交3477757eb2475555cf8d8df24bfb1deb0613880d,再打上鸿蒙化适配补丁后编译产出。
在深入流程前,必须明确两点关键前提:
- 实验特性,默认不开启:原文档明确说明,Hermes V1 当前仅是实验性功能,默认不启用,现阶段只能保证其"能正常运行",尚不能等同于稳定的生产能力。因此在生产项目中启用它需自行评估风险。
- 构建环境限制:Hermes V1 二进制只能在 macOS 上构建。仓库中 packages/react-native-harmony/scripts/build-hermes.sh 里对
hermesc主机构建、交叉编译工具链的使用方式也表明,整个构建链依赖 macOS 环境的工具链组织(bundle-harmony.ts中hermesc的路径解析同样按darwin/linux/win32三平台区分,但 Hermes V1 的源码构建环节以 macOS 为准)。
从源码结构看,Hermes V1 与社区版 Hermes 的差异主要体现在三处:
- 版本基线不同:社区版按
HERMES_TAG="hermes-v0.17.0"(对应 RN 0.86.3)浅克隆,而 V1 按HERMES_V1_BRANCH="250829098.0.0-stable"单分支克隆并锁定固定提交,产出版本号固定为250829098.0.17(见 build-hermes.sh 第 19-23 行)。 - 构型不同:V1 分支在 32 位(armeabi-v7a)上存在内联汇编约束问题无法构建,因此
ARCHITECTURES只含arm64-v8a与x86_64;社区版则额外包含armeabi-v7a。 - 鸿蒙化补丁不同:V1 应用 packages/react-native-harmony/scripts/hermesv1_cmakelists.patch,社区版应用
hermes_cmakelists.patch。
Hermes V1 补丁中的鸿蒙适配要点
V1 专属补丁hermesv1_cmakelists.patch的内容可以印证 V1 变体与鸿蒙(OHOS)系统的深度绑定:
- 移除 Android 专属依赖:注释掉
find_package(fbjni REQUIRED CONFIG)与add_subdirectory(android/intltest/java/com/facebook/hermes/test),使 Hermes 源码可在非 Android 平台(OHOS)上独立编译; - Linux/OHOS 内存标记适配:将
OSCompatPosix.cpp中PR_SET_VMA/vm_name相关的#ifdef __ANDROID__扩展为#if defined(__linux__) || defined(__ANDROID__),使匿名内存命名机制在 Linux 内核(鸿蒙底层)上生效; - 新增 restrace 内存追踪插桩:新增
include/hermes/Support/restrace.h,并在CompactArray、ArrayStorage、CopyableVector、DictPropertyMap、HadesGC、MallocGC等核心数据结构和 GC 路径上以弱符号方式(__attribute__((weak)))调用restrace/resTraceMove/resTraceFreeRegion,实现对RES_RN_HERMES_HEAP堆内存的分配、迁移、释放追踪,便于鸿蒙系统侧进行内存监控与异常定位; - 扩展 JSI 接口:为
Runtime增加getObjectProperties虚方法,用于枚举对象属性,供鸿蒙侧集成使用。
这些补丁内容决定了 V1 构建产物与社区版 Hermes 在行为上存在差异,因此不能直接复用社区版构建产物,必须按下文流程单独构建。
二、Step 1:在 macOS 上构建 Hermes V1 二进制
2.1 环境准备
在运行构建命令前,请确认:
- 使用macOS系统;
- 已配置好鸿蒙开发环境,即
DEVECO_SDK_HOME环境变量已定义。构建脚本会在开头直接检查该变量,未定义时立即报错退出:
if [ -z "$DEVECO_SDK_HOME" ]; then echo "Environment variable DEVECO_SDK_HOME is not defined" exit 1 fi- 已在本仓库根目录安装好依赖(
pnpm install),仓库根 package.json 已通过"overrides": { "hermes-compiler": "250829098.0.17" }将hermes-compiler固定到 Hermes V1 配套版本。
2.2 执行构建
在仓库根目录执行:
pnpm build:hermesv1该命令由根 package.json 的脚本"build:hermesv1": "pnpm run --filter ./packages/react-native-harmony build:hermesv1"转发到 packages/react-native-harmony/package.json 中定义的:
"build:hermesv1": "cross-env HERMES_V1_ENABLED=true sh ./scripts/build-hermes.sh", "build:hermesv1:debug": "cross-env HERMES_V1_ENABLED=true HERMES_ENABLE_DEBUGGER=true sh ./scripts/build-hermes.sh"两者差异仅在于HERMES_ENABLE_DEBUGGER是否置为true:
build:hermesv1:关闭调试器,CMAKE_BUILD_TYPE=MinSizeRel,编译选项-O3 -DNDEBUG,产物进入prebuilt/release/目录;build:hermesv1:debug:开启调试器(HERMES_ENABLE_DEBUGGER=True),编译选项-g,产物进入prebuilt/debug/目录。
2.3 构建脚本做了什么(源码级解读)
build-hermes.sh 的完整执行逻辑如下:
- 确认环境变量:检查
DEVECO_SDK_HOME(见上文),并从DEVECO_SDK_HOME/default/openharmony/native定位 OHOS Native SDK(cmake、ninja、工具链)。 - 克隆并固定 Hermes 源码:在
$OUTPUT_DIR/hermes(packages/react-native-harmony/scripts/out/hermes)克隆 V1 分支并git checkout到固定提交。 - 应用 V1 补丁:
git apply hermesv1_cmakelists.patch,若失败则提示人工修复后重新生成补丁。 - 确定目标架构:V1 模式下仅
arm64-v8a与x86_64(跳过 armeabi-v7a)。 - 先构建主机的
hermesc编译器:使用 OHOS SDK 的 cmake 配置-DJSI_DIR=$JSI_DIR -DCMAKE_BUILD_TYPE=Release并构建hermesc目标。这一步产出的hermesc会被作为"导入主机编译器"(IMPORT_HOST_COMPILERS)用于后续交叉编译。 - 交叉编译 Hermes 运行时:对每个架构,以
-DCMAKE_SYSTEM_NAME=OHOS、-DOHOS_ARCH=$ARCHITECTURE、-DOHOS_STL=c++_shared、-DCMAKE_TOOLCHAIN_FILE=ohos.toolchain.cmake、-DHERMES_IS_ANDROID=True、-DHERMES_RELEASE_VERSION="$HERMES_RELEASE_VERSION"、-DHERMES_ENABLE_INTL=False、-DHERMES_UNICODE_LITE=True、-DHERMESVM_HEAP_HV_MODE=HEAP_HV_PREFER32等参数配置,再用 ninja 构建hermesvm目标产出libhermesvm.so。 - 符号分离与产物拷贝:用
llvm-objcopy/objcopy对libhermesvm.so做--only-keep-debug提取.sym、--strip-debug剥离调试符号、--add-gnu-debuglink建立调试链接,并把libhermesvm.so、.sym、.debug.txt(含 Build ID、架构、构建类型、时间戳)拷贝到packages/tester/harmony/react_native_openharmony/src/main/cpp/third-party/prebuilt/{release|debug}/{arm64-v8a|x86_64}/目录下。
当前仓库 prebuilt 目录 中已可见debug/与release/两个目录,各含arm64-v8a、x86_64两个架构的libhermesvm.so、.sym与.debug.txt,正是该构建流程的产物落点。
三、Step 2:配置 Hermes 编译器覆盖(overrides)
Hermes V1 的字节码必须由配套的hermesc编译器生成,因此需要在仓库根目录的package.json中为hermes-compiler包添加覆盖版本:
"pnpm": { "overrides": { "hermes-compiler": "250829098.0.17" } }注:
250829098.0.17即为HERMES_V1_VERSION(见 build-hermes.sh 第 23 行),它与 V1 运行时版本严格对应,混用其他版本的编译器与运行时可能产生字节码版本不匹配。
随后执行安装,使覆盖生效:
pnpm install在仓库中,根 package.json 实际使用的是简化写法"overrides": { "hermes-compiler": "250829098.0.17" }(pnpm 的pnpm.overrides简写),效果与原文档中的完整写法一致。安装完成后,node_modules/hermes-compiler下即为 V1 配套的hermesc。
为什么编译器版本必须与运行时一致
打包链路中,bundle-harmony命令(packages/react-native-harmony-cli/src/commands/bundle-harmony.ts)会根据HERMES_V1_ENABLED环境变量选择编译器路径:
const isHermesV1Enabled = process.env.HERMES_V1_ENABLED?.toLowerCase() === 'true'; const HERMESC_PATH_PREFIX = pathUtils.normalize( isHermesV1Enabled ? './node_modules/hermes-compiler/hermesc' : './node_modules/react-native/sdks/hermesc/' );即:V1 模式默认使用node_modules/hermes-compiler/hermesc(这正是 overrides 替换的目标包),非 V1 模式使用react-native/sdks/hermesc。Hermes 的 HBC 字节码带版本标识,运行时加载字节码时会校验版本,因此编译器与运行时版本错配会导致运行期失败——这也是验证环节(下文)要专门检查字节码版本#0x62的原因。
四、Step 3:使用 Hermes V1 编译器打包 JavaScript
进入 tester 工程并执行 V1 打包:
cd packages/tester pnpm bundle:hermesv1对应的脚本定义在 packages/tester/package.json:
"bundle:hermesv1": "cross-env RNOH_TESTER_ONLY__TARGET_PLATFORM=harmony react-native bundle-harmony --dev=false --minify=true --js-engine=hermes --hermesc-dir ../../node_modules/hermes-compiler/hermesc"该脚本要点解析:
--dev=false --minify=true:生产模式,关闭警告并压缩;--js-engine=hermes:指示bundle-harmony生成HBC 字节码而非普通 JS 包。从 bundle-harmony.ts 看,jsEngine为hermes时默认输出文件名为hermes_bundle.hbc,并且只有当输出路径以.hbc结尾时才会走saveHbcBundle的字节码编译分支;--hermesc-dir ../../node_modules/hermes-compiler/hermesc:显式指定编译器为 V1 配套的hermesc。saveHbcBundle内部会按平台拼接二进制路径(osx-bin/hermesc、linux64-bin/hermesc、win64-bin/hermesc.exe),并校验该路径存在,否则抛出Couldn't find hermesc at ...的引导性错误;- 可通过
--hermesc-options追加传给hermesc的额外选项,例如--hermesc-options O g reuse-prop-cache(见bundle-harmony.ts的选项说明)。
打包完成后,字节码产物默认输出到harmony/entry/src/main/resources/rawfile/hermes_bundle.hbc,资源同时拷贝至harmony/entry/src/main/resources/rawfile/assets。
五、Step 4:配置原生构建以启用 V1 运行时
Hermes V1 在原生侧的启用通过 CMake 变量HERMES_V1_ENABLED控制。有两种方式:
方式 A:直接编辑 tester 工程的 CMakeLists.txt
编辑文件 packages/tester/harmony/react_native_openharmony/src/main/cpp/RNOH/JSEngine/hermes/CMakeLists.txt:
# 原来(第 1 行): set(HERMES_V1_ENABLED OFF CACHE BOOL "Build with support for Hermes v1") # 改为: set(HERMES_V1_ENABLED ON CACHE BOOL "Build with support for Hermes v1")方式 B:通过 CMake 命令行参数传入
在你的 cmake 构建配置中加入(具体方式取决于工程构建脚本组织):
-DHERMES_V1_ENABLED=ON在实际工程中,更常见的做法是在build-profile.json5的externalNativeOptions.arguments数组中加入"-DHERMES_V1_ENABLED=ON"。仓库中 tester 各模块的 build-profile.json5 已经通过arguments传入-DRNOH_APP_DIR、-DWITH_HITRACE_SYSTRACE=ON等参数,可仿照追加。
HERMES_V1_ENABLED 在构建链中的实际作用
- 在 tester 根 CMake 配置 packages/tester/harmony/react_native_openharmony/src/main/cpp/CMakeLists.txt 中:
if (USE_HERMES) set(HERMES_V1_ENABLED ON) endif(),即默认使用 Hermes 时 V1 即被置为 ON,并在第 106 行打印HERMES_V1_ENABLED is set to: ${HERMES_V1_ENABLED}供日志验证; - 在 Hermes 集成子 CMake packages/tester/harmony/react_native_openharmony/src/main/cpp/RNOH/JSEngine/hermes/CMakeLists.txt 中:当
HERMES_V1_ENABLED为真时,会向hermes_executor_common、bridgelesshermes、hermes_inspector_modern三个目标注入HERMES_V1_ENABLED=1编译宏(第 38-42 行)。该宏的作用可从 packages/react-native.patch 中看到:#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)这类条件编译逻辑表明,V1 模式下会跳过某些仅用于社区版调试器的适配分支(如HermesExecutorRuntimeAdapter、调试器强引用封装等),从而适配 V1 运行时与鸿蒙侧的集成差异; - 该 CMake 还会根据
HERMES_ENABLE_DEBUGGER选择链接prebuilt/debug/${OHOS_ARCH}/libhermesvm.so或prebuilt/release/${OHOS_ARCH}/libhermesvm.so——这正好对应 Step 1 中选择build:hermesv1还是build:hermesv1:debug构建。
六、Step 5:构建并运行应用
完成上述配置后,按 tester 工程的常规方式构建并运行:
cd packages/tester/harmony # 使用 DevEco Studio / hvigor 构建 HAP,或使用: pnpm harmony # 在 packages/tester 下,等价 react-native run-harmony应用启动时加载hermes_bundle.hbc,由 V1 运行时解释执行。
七、验证:确认 Hermes V1 真正生效
原文档提供了三层验证手段,由浅入深。
7.1 构建日志验证
在 CMake 配置输出中查找:
HERMES_V1_ENABLED is set to: ON该日志在 tester 根 CMakeLists.txt(第 106 行)、hermes 集成 CMakeLists.txt(第 2 行)以及 react-native-harmony.cmake(第 47 行)中均会打印,说明 V1 开关在各级 CMake 配置中均被正确传递。
7.2 字节码版本验证(objdump)
运行以下命令,检查输出中是否打印了#0x62:
objdump -d packages/tester/harmony/react_native_openharmony/src/main/cpp/third-party/prebuilt/debug/arm64-v8a/libhermesvm.so | grep -A 2 getBytecodeVersion | grep "mov.*#0x" | awk '{print $5, $6}'- 该命令反汇编
libhermesvm.so,在getBytecodeVersion符号附近查找mov ... #0x...立即数加载指令; 0x62(十进制 98)即 Hermes V1(250829098.0.17)对应的字节码版本号。若输出为#0x62,说明运行时支持的字节码版本与 V1 编译器产物一致;- 注意命令中路径为
debug/arm64-v8a,若构建的是 release 产物,应相应替换为prebuilt/release/arm64-v8a/libhermesvm.so; - 前提:需要本机安装
objdump/binutils。若不可用,可跳过此项,直接进行运行时验证。
7.3 运行时属性验证
在应用 JS 侧调用 Hermes 内部 API,检查返回的版本号:
HermesInternal.getRuntimeProperties()["OSS Release Version"];若 Hermes V1 正常运行,该调用应返回"250829098.0.17"——该版本字符串正是构建脚本中HERMES_V1_VERSION="250829098.0.17"(build-hermes.sh 第 23 行)通过-DHERMES_RELEASE_VERSION="$HERMES_RELEASE_VERSION"编译进运行时的,因此可作为运行时确实为 V1 的最直接证据。
八、常见问题与注意事项
- 构建必须使用 macOS:
pnpm build:hermesv1依赖 macOS 环境组织工具链与主机编译器,Windows/Linux 上无法完成 Hermes V1 源码构建;而使用编译好的二进制进行打包(Step 2-3)与原生集成(Step 4-5)不限于 macOS。 DEVECO_SDK_HOME未定义:构建脚本会在入口直接报错Environment variable DEVECO_SDK_HOME is not defined,请先完成鸿蒙原生开发环境配置。- hermesc 路径不存在:执行
bundle:hermesv1前请确认pnpm install已生效(overrides 已落地),否则saveHbcBundle会抛出Couldn't find hermesc at ...。 - 架构限制:Hermes V1 仅构建
arm64-v8a与x86_64,不支持 32 位架构;若目标设备/模拟器为 32 位,无法使用 V1。 - 实验性质:V1 当前只保证基本功能正常,官方(仓库说明)不承诺其生产级稳定性;社区版 Hermes(
hermes-v0.17.0)仍是默认基线。 - release/debug 产物要匹配:Step 1 中选择的构建模式(
build:hermesv1或build:hermesv1:debug)需与 Step 4 构建时的HERMES_ENABLE_DEBUGGER状态对应,CMake 会根据该变量从prebuilt/release或prebuilt/debug中选取libhermesvm.so。
九、结语:Hermes V1 启用路径一览
回顾全文,启用 Hermes V1 的完整链路为:
| 步骤 | 操作 | 关键命令/配置 | 产物/落点 |
|---|---|---|---|
| 1 | 构建 V1 二进制(仅 macOS) | pnpm build:hermesv1(或:debug) | third-party/prebuilt/{release\|debug}/{arm64-v8a,x86_64}/libhermesvm.so |
| 2 | 覆盖编译器版本 | pnpm.overrides.hermes-compiler = 250829098.0.17+pnpm install | node_modules/hermes-compiler/hermesc |
| 3 | 编译 JS 为 V1 字节码 | cd packages/tester && pnpm bundle:hermesv1 | hermes_bundle.hbc(rawfile) |
| 4 | 启用 V1 原生开关 | 编辑RNOH/JSEngine/hermes/CMakeLists.txt或-DHERMES_V1_ENABLED=ON | 编译宏HERMES_V1_ENABLED=1注入各 Hermes 目标 |
| 5 | 构建运行 | pnpm harmony/ DevEco 构建 | 应用加载 HBC 运行 |
| 验证 | 三层验证 | CMake 日志 /objdump ... #0x62/HermesInternal... | 确认 V1 生效 |
该链路中,"编译器版本覆盖 + 字节码打包 + 原生开关 + 运行时版本核对"四个环节环环相扣:编译器决定字节码格式,运行时决定能否加载该格式,任何一环版本错配都会导致失败。本文中涉及的构建脚本(build-hermes.sh)、V1 补丁(hermesv1_cmakelists.patch)、打包命令(bundle-harmony.ts)与各级 CMake 配置均已给出仓库内路径,读者可对照源码进一步深入验证。
- OpenHarmony
- 移动开发
- 跨平台
【免费下载链接】ohos_react_native
React Native鸿蒙化仓库
相关推荐
Hermes引擎全解析:从字节码到高性能React Native应用
Hermes引擎全解析:从字节码到高性能React Native应用 你是否还在为React Native应用启动慢、内存占用高而烦恼?本文将深入解析Faceb
语言运行时编译器移动开发从源码构建与运行 Hermes JS 引擎:CLI 工具、字节码编译与 React Native 集成指南
从源码构建与运行 Hermes JS 引擎:CLI 工具、字节码编译与 React Native 集成指南 Hermes 是 Meta 开源的 JavaScri
语言运行时编译器移动开发React Native 鸿蒙化(ohos_react_native)应用性能优化实战:Release 打包、LOG_VERBOSITY_LEVEL 与 Hermes HBC 字节码配置
React Native 鸿蒙化(ohos_react_native)应用性能优化实战:Release 打包、LOG_VERBOSITY_LEVEL 与 Her
OpenHarmony移动开发跨平台
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考