捆綁式 Hermes
本頁概述 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 版本一起建置和測試的 JS 引擎,可供您使用。
我們為什麼轉向「捆綁式 Hermes」
從歷史上看,React Native 和 Hermes 遵循兩個不同的發布流程,並具有不同的版本控制。具有不同版本和不同號碼的獨立發布在 OSS 生態系統中造成了混淆,因為不清楚特定版本的 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,並確保在建置 Hermes 時僅使用一個 JSI 副本。
有鑑於此,我們可以在每次發布 React Native 版本時都發布一個 Hermes 版本,並確保我們建置的 Hermes 引擎與我們發布的 React Native 版本完全相容。我們將這個版本的 Hermes 與我們正在進行的 React Native 版本一起發布,因此得名為捆綁式 Hermes。
這將如何影響應用程式開發人員
如簡介中所述,如果您是應用程式開發人員,則此變更不應直接影響您。
以下段落描述了我們在底層所做的變更,並為了透明度起見,解釋了部分基本原理。
iOS 使用者
在 iOS 上,我們已移動您正在使用的 hermes-engine
。
在 React Native 0.69 之前,使用者會下載一個 pod(您可以在此處找到 podspec)。
在 React Native 0.69 上,使用者將改用在 react-native
NPM 套件中的 sdks/hermes-engine/hermes-engine.podspec
檔案中定義的 podspec。該 podspec 依賴於 Hermes 的預先建置 tarball,我們將其上傳到 Maven 和 React Native GitHub 版本,作為 React Native 發布流程的一部分(即請參閱此版本的資產)。
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 Community Edition - 僅選取 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/react-native
儲存庫內的 facebook/hermes
儲存庫下載包含 Hermes 原始碼的 tarball。我們針對其他原生依賴項(Folly、Glog 等)也建立了類似的機制,並且我們調整了 Hermes 以遵循相同的設定。
當從 main
建置 React Native 時,我們將提取 facebook/hermes
的 main
分支的 tarball,並將其作為 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 實作細節
為了在 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 方法(即解壓縮 .aar
並提取 .so
檔案)來使用 fbjni
。hermes-engine
和其他程式庫改用 prefab 來使用 fbjni。我們正在研究在未來解決此問題,以便 Hermes 匯入將會是一行程式碼。
iOS 實作細節
iOS 實作依賴於一系列腳本,這些腳本位於以下位置
/scripts/hermes
。這些腳本包含下載 Hermes tarball、解壓縮並配置 iOS 建置的邏輯。如果您將hermes_enabled
欄位設定為true
,則會在pod install
時調用它們。/sdks/hermes-engine
。這些腳本包含實際建置 Hermes 的建置邏輯。它們是從facebook/hermes
儲存庫複製和改編而來,以便在 React Native 內正常運作。具體來說,utils
資料夾內的腳本負責為所有 Mac 平台建置 Hermes。
Hermes 是作為 CircleCI 上的 build_hermes_macos
Job 的一部分建置的。當使用已發布的 React Native 版本時,此 Job 將產生一個 tarball 作為工件,該 tarball 將由 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 版本,您可以透過在使用 CocoaPods 時將 CI
環境變數設定為 true
來強制從原始碼建置 Hermes:CI=true pod install
。
偵錯符號
Hermes 的預先建置工件預設不包含偵錯符號 (dSYM)。我們計劃在未來為每個版本發布這些偵錯符號。在此之前,如果您需要 Hermes 的偵錯符號,您將需要從原始碼建置 Hermes。hermes.framework.dSYM
將在建置目錄中與每個 Hermes 框架一起建立。
我擔心此變更正在影響我
我們想強調,這本質上是一個關於 Hermes 在哪裡建置以及如何在兩個儲存庫之間同步程式碼的組織變更。此變更應對我們的使用者完全透明。
從歷史上看,我們過去會為特定版本的 React Native 發布 Hermes 版本(例如 v0.11.0 for RN0.68.x
)。
使用「捆綁式 Hermes」,您可以改為依靠一個標籤,該標籤將代表在切割特定版本的 React Native 時使用的版本。