fix: Support RN 0.69 and use Hermes from source! 🎉 (#1186)
* wip * wip * Update CMakeLists.txt * Update CMakeLists.txt * Update android/build.gradle Co-authored-by: Tomek Zawadzki <tomekzawadzki98@gmail.com> Co-authored-by: Tomek Zawadzki <tomekzawadzki98@gmail.com>
This commit is contained in:
parent
312b82b9f6
commit
205e542cb6
@ -76,27 +76,47 @@ target_include_directories(
|
|||||||
file (GLOB LIBRN_DIR "${BUILD_DIR}/react-native-0*/jni/${ANDROID_ABI}")
|
file (GLOB LIBRN_DIR "${BUILD_DIR}/react-native-0*/jni/${ANDROID_ABI}")
|
||||||
|
|
||||||
if(${FOR_HERMES})
|
if(${FOR_HERMES})
|
||||||
file (GLOB LIBHERMES_DIR "${BUILD_DIR}/third-party-ndk/hermes/jni/${ANDROID_ABI}")
|
string(APPEND CMAKE_CXX_FLAGS " -DJS_RUNTIME_HERMES=1")
|
||||||
# Use Hermes
|
|
||||||
find_library(
|
if(${REACT_NATIVE_VERSION} LESS 69)
|
||||||
JS_ENGINE_LIB
|
# From `hermes-engine` npm package
|
||||||
hermes
|
target_include_directories(
|
||||||
PATHS ${LIBHERMES_DIR}
|
${PACKAGE_NAME}
|
||||||
NO_CMAKE_FIND_ROOT_PATH
|
PRIVATE
|
||||||
)
|
"${JS_RUNTIME_DIR}/android/include"
|
||||||
# Use Reanimated Hermes
|
)
|
||||||
file (GLOB LIBREANIMATED_DIR "${BUILD_DIR}/react-native-reanimated-*-hermes.aar/jni/${ANDROID_ABI}")
|
else()
|
||||||
|
# Bundled Hermes from module `com.facebook.react:hermes-engine` or project `:ReactAndroid:hermes-engine`
|
||||||
|
target_include_directories(
|
||||||
|
${PACKAGE_NAME}
|
||||||
|
PRIVATE
|
||||||
|
"${JS_RUNTIME_DIR}/API"
|
||||||
|
"${JS_RUNTIME_DIR}/public"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${PACKAGE_NAME}
|
||||||
|
"${BUILD_DIR}/third-party-ndk/hermes/jni/${ANDROID_ABI}/libhermes.so"
|
||||||
|
)
|
||||||
|
file (GLOB LIBREANIMATED_DIR "${BUILD_DIR}/react-native-reanimated-*-hermes.aar/jni/${ANDROID_ABI}")
|
||||||
else()
|
else()
|
||||||
file (GLOB LIBJSC_DIR "${BUILD_DIR}/android-jsc*.aar/jni/${ANDROID_ABI}")
|
file (GLOB LIBJSC_DIR "${BUILD_DIR}/android-jsc*.aar/jni/${ANDROID_ABI}")
|
||||||
# Use JSC
|
|
||||||
find_library(
|
# Use JSC
|
||||||
JS_ENGINE_LIB
|
find_library(
|
||||||
jscexecutor
|
JS_ENGINE_LIB
|
||||||
PATHS ${LIBRN_DIR}
|
jscexecutor
|
||||||
NO_CMAKE_FIND_ROOT_PATH
|
PATHS ${LIBRN_DIR}
|
||||||
)
|
NO_CMAKE_FIND_ROOT_PATH
|
||||||
# Use Reanimated JSC
|
)
|
||||||
file (GLOB LIBREANIMATED_DIR "${BUILD_DIR}/react-native-reanimated-*-jsc.aar/jni/${ANDROID_ABI}")
|
target_link_libraries(
|
||||||
|
${PACKAGE_NAME}
|
||||||
|
${JS_ENGINE_LIB}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use Reanimated JSC
|
||||||
|
file (GLOB LIBREANIMATED_DIR "${BUILD_DIR}/react-native-reanimated-*-jsc.aar/jni/${ANDROID_ABI}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_library(
|
find_library(
|
||||||
@ -105,12 +125,22 @@ find_library(
|
|||||||
PATHS ${LIBRN_DIR}
|
PATHS ${LIBRN_DIR}
|
||||||
NO_CMAKE_FIND_ROOT_PATH
|
NO_CMAKE_FIND_ROOT_PATH
|
||||||
)
|
)
|
||||||
find_library(
|
|
||||||
FOLLY_JSON_LIB
|
if(${REACT_NATIVE_VERSION} LESS 69)
|
||||||
folly_json
|
find_library(
|
||||||
PATHS ${LIBRN_DIR}
|
FOLLY_LIB
|
||||||
NO_CMAKE_FIND_ROOT_PATH
|
folly_json
|
||||||
)
|
PATHS ${LIBRN_DIR}
|
||||||
|
NO_CMAKE_FIND_ROOT_PATH
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
find_library(
|
||||||
|
FOLLY_LIB
|
||||||
|
folly_runtime
|
||||||
|
PATHS ${LIBRN_DIR}
|
||||||
|
NO_CMAKE_FIND_ROOT_PATH
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_library(
|
find_library(
|
||||||
REACT_NATIVE_JNI_LIB
|
REACT_NATIVE_JNI_LIB
|
||||||
@ -118,6 +148,7 @@ find_library(
|
|||||||
PATHS ${LIBRN_DIR}
|
PATHS ${LIBRN_DIR}
|
||||||
NO_CMAKE_FIND_ROOT_PATH
|
NO_CMAKE_FIND_ROOT_PATH
|
||||||
)
|
)
|
||||||
|
|
||||||
if(${REACT_NATIVE_VERSION} LESS 66)
|
if(${REACT_NATIVE_VERSION} LESS 66)
|
||||||
# JSI lib didn't exist on RN 0.65 and before. Simply omit it.
|
# JSI lib didn't exist on RN 0.65 and before. Simply omit it.
|
||||||
set (JSI_LIB "")
|
set (JSI_LIB "")
|
||||||
@ -144,16 +175,14 @@ find_library(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# linking
|
# linking
|
||||||
|
|
||||||
message(WARNING "VisionCamera linking: FOR_HERMES=${FOR_HERMES}")
|
message(WARNING "VisionCamera linking: FOR_HERMES=${FOR_HERMES}")
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
${PACKAGE_NAME}
|
${PACKAGE_NAME}
|
||||||
${LOG_LIB}
|
${LOG_LIB}
|
||||||
${JSI_LIB}
|
${JSI_LIB}
|
||||||
${JS_ENGINE_LIB} # <-- Hermes or JSC
|
|
||||||
${REANIMATED_LIB}
|
${REANIMATED_LIB}
|
||||||
${REACT_NATIVE_JNI_LIB}
|
${REACT_NATIVE_JNI_LIB}
|
||||||
${FBJNI_LIB}
|
${FBJNI_LIB}
|
||||||
${FOLLY_JSON_LIB}
|
${FOLLY_LIB}
|
||||||
android
|
android
|
||||||
)
|
)
|
||||||
|
@ -16,13 +16,35 @@ static def findNodeModules(baseDir) {
|
|||||||
}
|
}
|
||||||
throw new GradleException("VisionCamera: Failed to find node_modules/ path!")
|
throw new GradleException("VisionCamera: Failed to find node_modules/ path!")
|
||||||
}
|
}
|
||||||
|
static def findNodeModulePath(baseDir, packageName) {
|
||||||
|
def basePath = baseDir.toPath().normalize()
|
||||||
|
// Node's module resolution algorithm searches up to the root directory,
|
||||||
|
// after which the base path will be null
|
||||||
|
while (basePath) {
|
||||||
|
def candidatePath = Paths.get(basePath.toString(), "node_modules", packageName)
|
||||||
|
if (candidatePath.toFile().exists()) {
|
||||||
|
return candidatePath.toString()
|
||||||
|
}
|
||||||
|
basePath = basePath.getParent()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
def isNewArchitectureEnabled() {
|
||||||
|
// To opt-in for the New Architecture, you can either:
|
||||||
|
// - Set `newArchEnabled` to true inside the `gradle.properties` file
|
||||||
|
// - Invoke gradle with `-newArchEnabled=true`
|
||||||
|
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
|
||||||
|
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
||||||
|
}
|
||||||
|
|
||||||
def nodeModules = findNodeModules(projectDir)
|
def nodeModules = findNodeModules(projectDir)
|
||||||
logger.warn("VisionCamera: node_modules/ found at: ${nodeModules}")
|
logger.warn("VisionCamera: node_modules/ found at: ${nodeModules}")
|
||||||
def reactNative = new File("$nodeModules/react-native")
|
def reactNative = new File("$nodeModules/react-native")
|
||||||
|
def CMAKE_NODE_MODULES_DIR = project.getProjectDir().getParentFile().getParent()
|
||||||
def reactProperties = new Properties()
|
def reactProperties = new Properties()
|
||||||
file("$nodeModules/react-native/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) }
|
file("$nodeModules/react-native/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) }
|
||||||
|
def REACT_NATIVE_FULL_VERSION = reactProperties.getProperty("VERSION_NAME")
|
||||||
def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME").split("\\.")[1].toInteger()
|
def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME").split("\\.")[1].toInteger()
|
||||||
|
|
||||||
def FOR_HERMES = System.getenv("FOR_HERMES") == "True"
|
def FOR_HERMES = System.getenv("FOR_HERMES") == "True"
|
||||||
@ -31,6 +53,17 @@ rootProject.getSubprojects().forEach({project ->
|
|||||||
FOR_HERMES = project.ext.react.enableHermes
|
FOR_HERMES = project.ext.react.enableHermes
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
def jsRuntimeDir = {
|
||||||
|
if (FOR_HERMES) {
|
||||||
|
if (REACT_NATIVE_VERSION >= 69) {
|
||||||
|
return Paths.get(CMAKE_NODE_MODULES_DIR, "react-native", "sdks", "hermes")
|
||||||
|
} else {
|
||||||
|
return Paths.get(CMAKE_NODE_MODULES_DIR, "hermes-engine")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Paths.get(CMAKE_NODE_MODULES_DIR, "react-native", "ReactCommon", "jsi")
|
||||||
|
}
|
||||||
|
}.call()
|
||||||
logger.warn("VisionCamera: Building with ${FOR_HERMES ? "Hermes" : "JSC"}...")
|
logger.warn("VisionCamera: Building with ${FOR_HERMES ? "Hermes" : "JSC"}...")
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
@ -67,6 +100,16 @@ def getExtOrIntegerDefault(name) {
|
|||||||
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['VisionCamera_' + name]).toInteger()
|
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['VisionCamera_' + name]).toInteger()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def resolveBuildType() {
|
||||||
|
def buildType = "debug"
|
||||||
|
tasks.all({ task ->
|
||||||
|
if (task.name == "buildCMakeRelease") {
|
||||||
|
buildType = "release"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return buildType
|
||||||
|
}
|
||||||
|
|
||||||
// plugin.js file only exists since REA v2.
|
// plugin.js file only exists since REA v2.
|
||||||
def hasReanimated2 = file("${nodeModules}/react-native-reanimated/plugin.js").exists()
|
def hasReanimated2 = file("${nodeModules}/react-native-reanimated/plugin.js").exists()
|
||||||
def disableFrameProcessors = rootProject.ext.has("disableFrameProcessors") ? rootProject.ext.get("disableFrameProcessors").asBoolean() : false
|
def disableFrameProcessors = rootProject.ext.has("disableFrameProcessors") ? rootProject.ext.get("disableFrameProcessors").asBoolean() : false
|
||||||
@ -99,7 +142,8 @@ android {
|
|||||||
arguments '-DANDROID_STL=c++_shared',
|
arguments '-DANDROID_STL=c++_shared',
|
||||||
"-DREACT_NATIVE_VERSION=${REACT_NATIVE_VERSION}",
|
"-DREACT_NATIVE_VERSION=${REACT_NATIVE_VERSION}",
|
||||||
"-DNODE_MODULES_DIR=${nodeModules}",
|
"-DNODE_MODULES_DIR=${nodeModules}",
|
||||||
"-DFOR_HERMES=${FOR_HERMES}"
|
"-DFOR_HERMES=${FOR_HERMES}",
|
||||||
|
"-DJS_RUNTIME_DIR=${jsRuntimeDir}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,17 +272,14 @@ dependencies {
|
|||||||
//noinspection GradleDynamicVersion
|
//noinspection GradleDynamicVersion
|
||||||
extractJNI("com.facebook.fbjni:fbjni:+")
|
extractJNI("com.facebook.fbjni:fbjni:+")
|
||||||
|
|
||||||
def rnAAR = fileTree("${nodeModules}/react-native/android").matching({ it.include "**/**/*.aar" }).singleFile
|
def rnAarMatcher = "**/react-native/**/*${resolveBuildType()}.aar"
|
||||||
|
if (REACT_NATIVE_VERSION < 69) {
|
||||||
|
rnAarMatcher = "**/**/*.aar"
|
||||||
|
}
|
||||||
|
def rnAAR = fileTree("$reactNative/android").matching({ it.include rnAarMatcher }).singleFile
|
||||||
def jscAAR = fileTree("${nodeModules}/jsc-android/dist/org/webkit/android-jsc").matching({ it.include "**/**/*.aar" }).singleFile
|
def jscAAR = fileTree("${nodeModules}/jsc-android/dist/org/webkit/android-jsc").matching({ it.include "**/**/*.aar" }).singleFile
|
||||||
|
|
||||||
def inputFile = file("${nodeModules}/react-native/package.json")
|
|
||||||
def json = new JsonSlurper().parseText(inputFile.text)
|
|
||||||
def reactNativeVersion = json.version as String
|
|
||||||
def (major, minor, patch) = reactNativeVersion.tokenize('.')
|
|
||||||
|
|
||||||
def jsEngine = FOR_HERMES ? "hermes" : "jsc"
|
def jsEngine = FOR_HERMES ? "hermes" : "jsc"
|
||||||
def reaAAR = "${nodeModules}/react-native-reanimated/android/react-native-reanimated-${minor}-${jsEngine}.aar"
|
def reaAAR = "${nodeModules}/react-native-reanimated/android/react-native-reanimated-${REACT_NATIVE_VERSION}-${jsEngine}.aar"
|
||||||
|
|
||||||
extractJNI(files(rnAAR, jscAAR, reaAAR))
|
extractJNI(files(rnAAR, jscAAR, reaAAR))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +326,12 @@ if (ENABLE_FRAME_PROCESSORS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) {
|
task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) {
|
||||||
src("https://github.com/react-native-community/boost-for-react-native/releases/download/v${BOOST_VERSION.replace("_", ".")}-0/boost_${BOOST_VERSION}.tar.gz")
|
def transformedVersion = BOOST_VERSION.replace("_", ".")
|
||||||
|
def srcUrl = "https://boostorg.jfrog.io/artifactory/main/release/${transformedVersion}/source/boost_${BOOST_VERSION}.tar.gz"
|
||||||
|
if (REACT_NATIVE_VERSION < 69) {
|
||||||
|
srcUrl = "https://github.com/react-native-community/boost-for-react-native/releases/download/v${transformedVersion}-0/boost_${BOOST_VERSION}.tar.gz"
|
||||||
|
}
|
||||||
|
src(srcUrl)
|
||||||
onlyIfNewer(true)
|
onlyIfNewer(true)
|
||||||
overwrite(false)
|
overwrite(false)
|
||||||
dest(boost_file)
|
dest(boost_file)
|
||||||
@ -394,26 +440,95 @@ if (ENABLE_FRAME_PROCESSORS) {
|
|||||||
|
|
||||||
prepareThirdPartyNdkHeaders.mustRunAfter createNativeDepsDirectories
|
prepareThirdPartyNdkHeaders.mustRunAfter createNativeDepsDirectories
|
||||||
|
|
||||||
|
/*
|
||||||
|
COPY-PASTE from react-native-reanimated.
|
||||||
|
Vision Camera includes "hermes/hermes.h" header file in `NativeProxy.cpp`.
|
||||||
|
Previously, we used header files from `hermes-engine` package in `node_modules`.
|
||||||
|
Starting from React Native 0.69, Hermes is no longer distributed as package on NPM.
|
||||||
|
On the new architecture, Hermes is downloaded from GitHub and then compiled from sources.
|
||||||
|
However, on the old architecture, we need to download Hermes header files on our own
|
||||||
|
as well as unzip Hermes AAR in order to obtain `libhermes.so` shared library.
|
||||||
|
For more details, see https://reactnative.dev/architecture/bundled-hermes
|
||||||
|
or https://github.com/reactwg/react-native-new-architecture/discussions/4
|
||||||
|
*/
|
||||||
|
if (REACT_NATIVE_VERSION >= 69 && !isNewArchitectureEnabled()) {
|
||||||
|
// copied from `react-native/ReactAndroid/hermes-engine/build.gradle`
|
||||||
|
|
||||||
|
def customDownloadDir = System.getenv("REACT_NATIVE_DOWNLOADS_DIR")
|
||||||
|
def downloadDir = customDownloadDir ? new File(customDownloadDir) : new File(reactNative, "sdks/download")
|
||||||
|
|
||||||
|
// By default we are going to download and unzip hermes inside the /sdks/hermes folder
|
||||||
|
// but you can provide an override for where the hermes source code is located.
|
||||||
|
def hermesDir = System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR") ?: new File(reactNative, "sdks/hermes")
|
||||||
|
|
||||||
|
def hermesVersion = "main"
|
||||||
|
def hermesVersionFile = new File(reactNative, "sdks/.hermesversion")
|
||||||
|
if (hermesVersionFile.exists()) {
|
||||||
|
hermesVersion = hermesVersionFile.text
|
||||||
|
}
|
||||||
|
|
||||||
|
task downloadHermes(type: Download) {
|
||||||
|
src("https://github.com/facebook/hermes/tarball/${hermesVersion}")
|
||||||
|
onlyIfNewer(true)
|
||||||
|
overwrite(false)
|
||||||
|
dest(new File(downloadDir, "hermes.tar.gz"))
|
||||||
|
}
|
||||||
|
|
||||||
|
task unzipHermes(dependsOn: downloadHermes, type: Copy) {
|
||||||
|
from(tarTree(downloadHermes.dest)) {
|
||||||
|
eachFile { file ->
|
||||||
|
// We flatten the unzip as the tarball contains a `facebook-hermes-<SHA>`
|
||||||
|
// folder at the top level.
|
||||||
|
if (file.relativePath.segments.size() > 1) {
|
||||||
|
file.relativePath = new org.gradle.api.file.RelativePath(!file.isDirectory(), file.relativePath.segments.drop(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
into(hermesDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
task prepareHermes() {
|
task prepareHermes() {
|
||||||
doLast {
|
if (REACT_NATIVE_VERSION >= 69) {
|
||||||
def hermesPackagePath = file("${nodeModules}/hermes-engine")
|
if (!isNewArchitectureEnabled()) {
|
||||||
if (!hermesPackagePath.exists()) {
|
dependsOn(unzipHermes)
|
||||||
throw new GradleScriptException("Could not find the hermes-engine npm package", null)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def hermesAAR = file("$hermesPackagePath/android/hermes-debug.aar")
|
doLast {
|
||||||
if (!hermesAAR.exists()) {
|
def hermesAAR = file("$reactNative/android/com/facebook/react/hermes-engine/$REACT_NATIVE_FULL_VERSION/hermes-engine-$REACT_NATIVE_FULL_VERSION-${resolveBuildType()}.aar") // e.g. hermes-engine-0.70.0-rc.1-debug.aar
|
||||||
throw new GradleScriptException("The hermes-engine npm package is missing \"android/hermes-debug.aar\"", null)
|
if (!hermesAAR.exists()) {
|
||||||
}
|
throw new GradleScriptException("Could not find hermes-engine AAR", null)
|
||||||
|
}
|
||||||
|
|
||||||
def soFiles = zipTree(hermesAAR).matching({ it.include "**/*.so" })
|
def soFiles = zipTree(hermesAAR).matching({ it.include "**/*.so" })
|
||||||
|
|
||||||
copy {
|
copy {
|
||||||
from soFiles
|
from soFiles
|
||||||
from "$reactNative/ReactAndroid/src/main/jni/first-party/hermes/Android.mk"
|
from "$reactNative/ReactAndroid/src/main/jni/first-party/hermes/Android.mk"
|
||||||
into "$thirdPartyNdkDir/hermes"
|
into "$thirdPartyNdkDir/hermes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doLast {
|
||||||
|
def hermesPackagePath = findNodeModulePath(projectDir, "hermes-engine")
|
||||||
|
if (!hermesPackagePath) {
|
||||||
|
throw new GradleScriptException("Could not find the hermes-engine npm package", null)
|
||||||
|
}
|
||||||
|
|
||||||
|
def hermesAAR = file("$hermesPackagePath/android/hermes-debug.aar")
|
||||||
|
if (!hermesAAR.exists()) {
|
||||||
|
throw new GradleScriptException("The hermes-engine npm package is missing \"android/hermes-debug.aar\"", null)
|
||||||
|
}
|
||||||
|
|
||||||
|
def soFiles = zipTree(hermesAAR).matching({ it.include "**/*.so" })
|
||||||
|
|
||||||
|
copy {
|
||||||
|
from soFiles
|
||||||
|
from "$reactNative/ReactAndroid/src/main/jni/first-party/hermes/Android.mk"
|
||||||
|
into "$thirdPartyNdkDir/hermes"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareHermes.mustRunAfter prepareThirdPartyNdkHeaders
|
prepareHermes.mustRunAfter prepareThirdPartyNdkHeaders
|
||||||
|
Loading…
Reference in New Issue
Block a user