捆绑式 Hermes
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
本文概述了 Hermes 和 React Native 的构建机制。
如需在应用中使用 Hermes 的具体操作指南,请参阅另一篇文档:使用 Hermes
请注意:本文属于技术深度解析,主要面向基于 Hermes 或 React Native 开发扩展组件的用户。普通 React Native 用户无需深入了解 React Native 与 Hermes 的交互细节。
什么是「捆绑式 Hermes」
从 React Native 0.69.0 开始,每个 React Native 版本都将配套构建对应的 Hermes 版本。我们将这种分发模式称为 捆绑式 Hermes。
从 0.69 版本起,您始终可以使用与每个 React Native 版本配套构建并测试的 JavaScript 引擎。
为何采用「捆绑式 Hermes」
历史上,React Native 和 Hermes 采用两套独立的发布流程和版本号体系。这种独立发布模式导致开源生态出现混淆——开发者难以确定特定 Hermes 版本是否兼容特定 React Native 版本(例如需要明确知道 Hermes 0.11.0 仅兼容 React Native 0.68.0 等)。
Hermes 和 React Native 共享 JSI 代码(Hermes 代码在此,React Native 代码在此)。若两份 JSI 代码不同步,构建的 Hermes 将无法兼容对应 React Native 版本。您可在此处详细了解该 ABI 兼容性问题。
为解决此问题,我们扩展了 React Native 发布流程:在构建 Hermes 时下载并编译其源代码,同时确保仅使用单份 JSI 代码。
由此,我们能在发布每个 React Native 版本时同步发布配套的 Hermes 版本,并确保该 Hermes 引擎与当前 React Native 版本完全兼容。我们将此 Hermes 版本与 React Native 版本共同分发,故命名为「捆绑式 Hermes」。
对应用开发者的影响
如开篇所述,如果您是应用开发者,此变更不会直接影响您的开发工作。
以下段落将详细说明底层变更及其设计考量,以便保持技术透明度。
iOS 用户
在 iOS 平台,我们调整了您使用的 hermes-engine 依赖来源。
在 React Native 0.69 之前,用户需下载 CocoaPods 依赖(相关 podspec 文件在此)。
在 React Native 0.69 中,用户将改用 react-native NPM 包内 sdks/hermes-engine/hermes-engine.podspec 定义的 podspec。该 podspec 依赖预构建的 Hermes 压缩包,此压缩包会作为 React Native 发布流程的一部分上传至 Maven 和 GitHub Release(例如此版本的资源文件)。
Android 用户
在 Android 平台,我们将按以下方式更新默认模板中的 android/app/build.gradle 文件:
dependencies {
// ...
if (enableHermes) {
+ implementation("com.facebook.react:hermes-engine:+") {
+ exclude group:'com.facebook.fbjni'
+ }
- def hermesPath = "../../node_modules/hermes-engine/android/";
- debugImplementation files(hermesPath + "hermes-debug.aar")
- releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
在 React Native 0.69 之前,用户需要从 hermes-engine NPM 包中引入 hermes-debug.aar 和 hermes-release.aar。
在 React Native 0.69 中,用户将从 react-native NPM 包的 android/com/facebook/react/hermes-engine/ 目录中获取 Android 多构建变体产物。
请注意,我们将在未来的 React Native 版本中完全移除对 hermes-engine 的依赖。
使用新架构的 Android 用户
由于本地代码构建机制的特性(即 NDK 的使用方式),采用新架构的用户将从源代码构建 Hermes。
这使得新架构用户的 React Native 和 Hermes 构建机制保持一致(两者都将从源码构建)。 这意味着此类 Android 用户在首次构建时可能会遇到构建性能下降的问题。
您可以在加速构建流程页面找到优化构建时间、减少影响的指导方案。
在 Windows 上使用新架构的 Android 用户
在 Windows 机器上使用新架构构建 React Native 应用的用户,需要遵循以下额外步骤确保构建正常工作:
-
确保环境配置正确,已安装 Android SDK 和 node
-
通过 Chocolatey 安装 cmake
-
安装以下任一工具:
- Visual Studio 2022 生成工具
- Visual Studio 22 社区版 - 仅勾选 C++ 桌面开发即可
-
确保正确配置了 Visual Studio 命令提示符,因为该环境会配置必要的 C++ 编译器环境变量
-
在 Visual Studio 命令提示符中执行
npx react-native run-android运行应用
用户是否仍可使用其他引擎?
可以,用户可自由启用/禁用 Hermes(通过 Android 的 enableHermes 参数或 iOS 的 hermes_enabled 参数)。
"捆绑式 Hermes"的变更仅影响 Hermes 的构建和打包方式。
从 React Native 0.70 开始,enableHermes/hermes_enabled 的默认值将设为 true。
对贡献者和扩展开发者的影响
如果您是 React Native 贡献者,或正在开发基于 React Native/Hermes 的扩展,请继续阅读了解捆绑式 Hermes 的工作机制。
捆绑式 Hermes 的底层原理是什么?
该机制依赖于从 facebook/hermes 仓库下载源代码压缩包到 facebook/react-native 仓库。此机制与其他原生依赖项(Folly、Glog 等)的处理方式一致,我们将 Hermes 也纳入了相同体系。
在从 main 构建 React Native 时,我们会获取 facebook/hermes 的 main 分支的压缩包,并将其作为 React Native 构建流程的一部分进行编译。
在从发布分支(例如 0.69-stable)构建 React Native 时,我们会使用 Hermes 仓库的特定标签来同步两个仓库的代码。使用的标签名称将存储在 React Native 发布分支的 sdks/.hermesversion 文件中(例如 0.69 发布分支上的该文件)。
从某种意义上说,你可以将此方法类比为 git 子模块。
如果你基于 Hermes 进行开发,可以通过这些标签确认构建 React Native 时使用的 Hermes 版本,因为标签名称中会包含 React Native 版本号(例如 hermes-2022-05-20-RNv0.69.0-ee8941b8874132b8f83e4486b63ed5c19fc3f111)。
Android 实现细节
为实现此功能,我们在 React Native 的 /ReactAndroid/hermes-engine 目录中新增了构建流程,负责编译 Hermes 并打包供使用(更多背景参见此处)。
现在可以通过调用以下命令触发 Hermes 引擎构建:
// Build a debug version of Hermes
./gradlew :ReactAndroid:hermes-engine:assembleDebug
// Build a release version of Hermes
./gradlew :ReactAndroid:hermes-engine:assembleRelease
来自 React Native main 分支。
你无需在机器上安装额外工具(如 cmake、ninja 或 python3),因为我们已配置构建流程使用 NDK 自带的工具版本。
在 Gradle 使用端,我们也进行了优化:从 releaseImplementation 和 debugImplementation 改为使用 implementation。这是因为新版 hermes-engine Android 组件支持变体感知,能自动匹配应用的调试版/发布版引擎。即使你使用 staging 或其他构建类型/风味也无需额外配置。
但此变更导致模板中需要保留这行配置:
exclude group:'com.facebook.fbjni'
这是因为 React Native 采用非 Prefab 方式使用 fbjni(即解压 .aar 提取 .so 文件),而 Hermes-engine 等库使用 Prefab 方式引用 fbjni。我们正在研究解决此问题,未来引入 Hermes 将只需单行配置。
iOS 实现细节
iOS 实现依赖于以下位置的系列脚本:
-
/scripts/hermes:这些脚本包含下载 Hermes 压缩包、解压及配置 iOS 构建的逻辑。当hermes_enabled设为true时,执行pod install将自动调用它们。 -
/sdks/hermes-engine:这些脚本包含实际的 Hermes 构建逻辑,它们从facebook/hermes仓库复制并适配,确保能在 React Native 环境中正常运行。其中utils目录的脚本专门负责为所有 Mac 平台构建 Hermes。
Hermes 在 CircleCI 的 build_hermes_macos 任务中构建,产出的压缩包将作为产物。发布 React Native 版本时,hermes-engine podspec 会下载该压缩包(此处是 React Native 0.69 在 build_hermes_macos 中生成的产物示例)。
预构建的 Hermes
如果当前使用的 React Native 版本没有预构建产物(例如,你可能在使用来自 main 分支的 React Native),那么 Hermes 就需要从源代码构建。首先,Hermes 编译器 hermesc 会在 pod install 过程中为 macOS 构建,然后 Hermes 本身将作为 Xcode 构建流程的一部分,使用 build-hermes-xcode.sh 脚本来构建。
从源代码构建 Hermes
当使用来自 main 分支的 React Native 时,Hermes 总是从源代码构建。如果你使用的是稳定的 React Native 版本,可以通过将环境变量 CI 设置为 true 在使用 CocoaPods 时强制从源代码构建:CI=true pod install。
调试符号
默认情况下,Hermes 的预构建产物不包含调试符号(dSYMs)。我们计划在未来为每个版本分发这些调试符号。在此之前,如果你需要 Hermes 的调试符号,就需要从源代码构建。构建目录中会为每个 Hermes 框架生成对应的 hermes.framework.dSYM 文件。
我担心这个变更会影响到我
我们想强调,这本质上是对 Hermes 构建位置以及两个仓库间代码同步方式的组织结构调整。这一变更对用户而言应完全透明。
历史上,我们曾为特定版本的 React Native 发布 Hermes(例如 v0.11.0 for RN0.68.x)。
使用 'Bundled Hermes' 后,你可以依赖一个标签来确认发布特定 React Native 版本时所使用的 Hermes 版本。