import com.android.Version import org.apache.tools.ant.filters.ReplaceTokens import org.apache.tools.ant.taskdefs.condition.Os import groovy.json.JsonSlurper import javax.inject.Inject import java.nio.file.Files import java.nio.file.Paths /** * Finds the path of the installed npm package with the given name using Node's * module resolution algorithm, which searches "node_modules" directories up to * the file system root. This handles various cases, including: * * - Working in the open-source RN repo: * Gradle: /path/to/react-native/ReactAndroid * Node module: /path/to/react-native/node_modules/[package] * * - Installing RN as a dependency of an app and searching for hoisted * dependencies: * Gradle: /path/to/app/node_modules/react-native/ReactAndroid * Node module: /path/to/app/node_modules/[package] * * - Working in a larger repo (e.g., Facebook) that contains RN: * Gradle: /path/to/repo/path/to/react-native/ReactAndroid * Node module: /path/to/repo/node_modules/[package] * * The search begins at the given base directory (a File object). The returned * path is a string. */ 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 safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback } def safeAppExtGet(prop, fallback) { def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } appProject?.ext?.has(prop) ? appProject.ext.get(prop) : fallback } def resolveBuildType() { Gradle gradle = getGradle() String tskReqStr = gradle.getStartParameter().getTaskRequests()['args'].toString() return tskReqStr.contains('Release') ? 'release' : 'debug' } def isReanimatedExampleApp() { return safeAppExtGet("isReanimatedExampleApp", false) } 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 resolveReactNativeDirectory() { def reactNativeLocation = safeAppExtGet("REACT_NATIVE_NODE_MODULES_DIR", null) if (reactNativeLocation != null) { return file(reactNativeLocation) } if (isReanimatedExampleApp()) { return file("$projectDir/../${getPlaygroundAppName()}/node_modules/react-native") } // monorepo workaround // react-native can be hoisted or in project's own node_modules def reactNativeFromProjectNodeModules = file("${rootProject.projectDir}/../node_modules/react-native") if (reactNativeFromProjectNodeModules.exists()) { return reactNativeFromProjectNodeModules } def reactNativeFromNodeModulesWithReanimated = file("${projectDir}/../../react-native") if (reactNativeFromNodeModulesWithReanimated.exists()) { return reactNativeFromNodeModulesWithReanimated } throw new GradleException( "[Reanimated] Unable to resolve react-native location in node_modules. You should project extension property (in `app/build.gradle`) `REACT_NATIVE_NODE_MODULES_DIR` with path to react-native." ) } def getPlaygroundAppName() { // only for the development String playgroundAppName = "" try { rootProject.getSubprojects().forEach({project -> if (project.plugins.hasPlugin("com.android.application")) { var projectCatalogAbsolutePath = project.projectDir.toString().replace("/android/app", "") var slashPosition = projectCatalogAbsolutePath.lastIndexOf("/") playgroundAppName = projectCatalogAbsolutePath.substring(slashPosition + 1) } }) } catch (_) { throw new GradleException("[Reanimated] Couldn't determine playground app name.") } return playgroundAppName } def getReanimatedVersion() { def inputFile = file(projectDir.path + '/../package.json') def json = new JsonSlurper().parseText(inputFile.text) return json.version } def getReanimatedMajorVersion() { def (major, minor, patch) = getReanimatedVersion().tokenize('.') return major.toInteger() } def toPlatformFileString(String path) { if (Os.isFamily(Os.FAMILY_WINDOWS)) { path = path.replace(File.separatorChar, '/' as char) } return path } def reactNativeRootDir = resolveReactNativeDirectory() def reactProperties = new Properties() file("$reactNativeRootDir/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) } def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME") def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.startsWith("0.0.0-") ? 1000 : REACT_NATIVE_VERSION.split("\\.")[1].toInteger() def REANIMATED_VERSION = getReanimatedVersion() def REANIMATED_MAJOR_VERSION = getReanimatedMajorVersion() def IS_NEW_ARCHITECTURE_ENABLED = isNewArchitectureEnabled() // for React Native <= 0.70 def BOOST_VERSION = reactProperties.getProperty("BOOST_VERSION") def DOUBLE_CONVERSION_VERSION = reactProperties.getProperty("DOUBLE_CONVERSION_VERSION") def FOLLY_VERSION = reactProperties.getProperty("FOLLY_VERSION") def GLOG_VERSION = reactProperties.getProperty("GLOG_VERSION") def FBJNI_VERSION = "0.3.0" // We download various C++ open-source dependencies into downloads. // We then copy both the downloaded code and our custom makefiles and headers into third-party-ndk. // After that we build native code from src/main/jni with module path pointing at third-party-ndk. def customDownloadsDir = System.getenv("REACT_NATIVE_DOWNLOADS_DIR") def downloadsDir = customDownloadsDir ? new File(customDownloadsDir) : new File("$buildDir/downloads") def thirdPartyNdkDir = new File("$buildDir/third-party-ndk") def reactNativeThirdParty = new File("$reactNativeRootDir/ReactAndroid/src/main/jni/third-party") def reactNativeAndroidDownloadDir = new File("$reactNativeRootDir/ReactAndroid/build/downloads") def prefabHeadersDir = project.file("$buildDir/prefab-headers/reanimated") def JS_RUNTIME = { // Override JS runtime with environment variable if (System.getenv("JS_RUNTIME")) { return System.getenv("JS_RUNTIME") } // Enable V8 runtime if react-native-v8 is installed def v8Project = rootProject.getSubprojects().find { project -> project.name == "react-native-v8" } if (v8Project != null) { return "v8" } // Check if Hermes is enabled in app setup def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } if ((REACT_NATIVE_MINOR_VERSION >= 71 && appProject?.hermesEnabled?.toBoolean()) || appProject?.ext?.react?.enableHermes?.toBoolean()) { return "hermes" } // Use JavaScriptCore (JSC) by default return "jsc" }.call() def jsRuntimeDir = { if (JS_RUNTIME == "hermes") { if (REACT_NATIVE_MINOR_VERSION >= 69) { return Paths.get(reactNativeRootDir.path, "sdks", "hermes") } else { return Paths.get(reactNativeRootDir.path, "..", "hermes-engine") } } else if (JS_RUNTIME == "v8") { return findProject(":react-native-v8").getProjectDir().getParent() } else { return Paths.get(reactNativeRootDir.path, "ReactCommon", "jsi") } }.call() def reactNativeArchitectures() { def value = project.getProperties().get("reactNativeArchitectures") return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] } buildscript { repositories { google() mavenCentral() maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath "com.android.tools.build:gradle:7.3.1" classpath "de.undercouch:gradle-download-task:5.0.1" classpath "com.diffplug.spotless:spotless-plugin-gradle:6.11.0" } } if (project == rootProject) { apply from: "spotless.gradle" } apply plugin: "com.android.library" apply plugin: "maven-publish" apply plugin: "de.undercouch.download" android { compileSdkVersion safeExtGet("compileSdkVersion", 30) def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION if (agpVersion.tokenize('.')[0].toInteger() >= 7) { namespace "com.swmansion.reanimated" } if (rootProject.hasProperty("ndkPath")) { ndkPath rootProject.ext.ndkPath } if (rootProject.hasProperty("ndkVersion")) { ndkVersion rootProject.ext.ndkVersion } buildFeatures { if (REACT_NATIVE_MINOR_VERSION > 68) { prefab true prefabPublishing true buildConfig true } } prefab { reanimated { headers prefabHeadersDir.absolutePath } } defaultConfig { minSdkVersion safeExtGet("minSdkVersion", 16) targetSdkVersion safeExtGet("targetSdkVersion", 30) versionCode 1 versionName "1.0" buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", IS_NEW_ARCHITECTURE_ENABLED.toString()) buildConfigField("String", "REANIMATED_VERSION_JAVA", "\"${REANIMATED_VERSION}\"") externalNativeBuild { cmake { arguments "-DANDROID_STL=c++_shared", "-DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}", "-DANDROID_TOOLCHAIN=clang", REACT_NATIVE_MINOR_VERSION < 71 ? "-DBOOST_VERSION=${BOOST_VERSION}" : "-DBOOST_VERSION=", "-DREACT_NATIVE_DIR=${toPlatformFileString(reactNativeRootDir.path)}", "-DJS_RUNTIME=${JS_RUNTIME}", "-DJS_RUNTIME_DIR=${jsRuntimeDir}", "-DIS_NEW_ARCHITECTURE_ENABLED=${IS_NEW_ARCHITECTURE_ENABLED}", "-DIS_REANIMATED_EXAMPLE_APP=${isReanimatedExampleApp()}", "-DREANIMATED_VERSION=${REANIMATED_VERSION}" abiFilters (*reactNativeArchitectures()) } } buildConfigField("boolean", "IS_INTERNAL_BUILD", "false") buildConfigField("int", "EXOPACKAGE_FLAGS", "0") buildConfigField("int", "REACT_NATIVE_MINOR_VERSION", REACT_NATIVE_MINOR_VERSION.toString()) consumerProguardFiles 'proguard-rules.pro' } externalNativeBuild { cmake { path "CMakeLists.txt" } } buildTypes { debug { externalNativeBuild { cmake { if (JS_RUNTIME == "hermes") { arguments "-DHERMES_ENABLE_DEBUGGER=1" } else { arguments "-DHERMES_ENABLE_DEBUGGER=0" } } } } release { externalNativeBuild { cmake { arguments "-DHERMES_ENABLE_DEBUGGER=0" } } } } lintOptions { abortOnError false } packagingOptions { doNotStrip resolveBuildType() == 'debug' ? "**/**/*.so" : '' excludes = [ "META-INF", "META-INF/**", "**/libc++_shared.so", "**/libfbjni.so", "**/libjsi.so", "**/libfolly_json.so", "**/libfolly_runtime.so", "**/libglog.so", "**/libhermes.so", "**/libhermes-executor-debug.so", "**/libhermes_executor.so", "**/libreactnativejni.so", "**/libturbomodulejsijni.so", "**/libreact_nativemodule_core.so", "**/libjscexecutor.so", "**/libv8executor.so", ] } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn(packageNdkLibs) } configurations { extractHeaders extractSO } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } packagingOptions { // For some reason gradle only complains about the duplicated version of librrc_root and libreact_render libraries // while there are more libraries copied in intermediates folder of the lib build directory, we exclude // only the ones that make the build fail (ideally we should only include libreanimated but we // are only allowed to specify exlude patterns) exclude "**/libreact_render*.so" exclude "**/librrc_root.so" } sourceSets.main { java { if (IS_NEW_ARCHITECTURE_ENABLED) { srcDirs += "src/fabric/java" } else { srcDirs += "src/paper/java" } // messageQueueThread if (REANIMATED_MAJOR_VERSION > 2) { if (REACT_NATIVE_MINOR_VERSION <= 67) { srcDirs += "src/reactNativeVersionPatch/messageQueueThread/67" } else if (REACT_NATIVE_MINOR_VERSION <= 72) { srcDirs += "src/reactNativeVersionPatch/messageQueueThread/72" } else { srcDirs += "src/reactNativeVersionPatch/messageQueueThread/latest" } } // ReanimatedUIManager & ReanimatedUIImplementation if (REACT_NATIVE_MINOR_VERSION <= 70) { srcDirs += "src/reactNativeVersionPatch/ReanimatedUIManager/70" } else { srcDirs += "src/reactNativeVersionPatch/ReanimatedUIManager/latest" } // ReactFeatureFlags if (IS_NEW_ARCHITECTURE_ENABLED) { if (REACT_NATIVE_MINOR_VERSION <= 72) { srcDirs += "src/reactNativeVersionPatch/ReactFeatureFlagsWrapper/72" } else { srcDirs += "src/reactNativeVersionPatch/ReactFeatureFlagsWrapper/latest" } } } } } def assertLatestReactNativeWithNewArchitecture = task assertLatestReactNativeWithNewArchitectureTask { onlyIf { IS_NEW_ARCHITECTURE_ENABLED && REANIMATED_MAJOR_VERSION == 3 && REACT_NATIVE_MINOR_VERSION < 72 } doFirst { // If you change the minimal React Native version remember to update Compatibility Table in docs throw new GradleException( "[Reanimated] Outdated version of React Native for New Architecture. Reanimated " + REANIMATED_VERSION + " supports the New Architecture on React Native 0.72.0+. See https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#outdated-version-of-react-native-for-new-architecture for more information." ) } } def assertMinimalReactNativeVersion = task assertMinimalReactNativeVersionTask { onlyIf { REACT_NATIVE_MINOR_VERSION < 66 } doFirst { // If you change the minimal React Native version remember to update Compatibility Table in docs throw new GradleException("[Reanimated] Unsupported React Native version. Please use 0.66 or newer.") } } task prepareHeadersForPrefab(type: Copy) { from("$projectDir/src/main/cpp") from("$projectDir/../Common/cpp/AnimatedSensor") from("$projectDir/../Common/cpp/Fabric") from("$projectDir/../Common/cpp/LayoutAnimations") from("$projectDir/../Common/cpp/NativeModules") from("$projectDir/../Common/cpp/ReanimatedRuntime") from("$projectDir/../Common/cpp/Registries") from("$projectDir/../Common/cpp/SharedItems") from("$projectDir/../Common/cpp/Tools") include("*.h") into(prefabHeadersDir) } tasks.preBuild { dependsOn assertLatestReactNativeWithNewArchitecture, assertMinimalReactNativeVersion } task cleanCmakeCache() { tasks.getByName("clean").dependsOn(cleanCmakeCache) doFirst { delete "${projectDir}/.cxx" } } task printVersions { println "Android gradle plugin: ${Version.ANDROID_GRADLE_PLUGIN_VERSION}" println "Gradle: ${project.gradle.gradleVersion}" } task createNativeDepsDirectories() { downloadsDir.mkdirs() thirdPartyNdkDir.mkdirs() prefabHeadersDir.mkdirs() } def resolveTaskFactory(String taskName, String artifactLocalName, File reactNativeAndroidDownloadDir, File reanimatedDownloadDir) { return tasks.create(name: taskName, dependsOn: createNativeDepsDirectories, type: Copy) { from reactNativeAndroidDownloadDir include artifactLocalName into reanimatedDownloadDir onlyIf { // First we check whether the file is already in our download directory if (file("$reanimatedDownloadDir/$artifactLocalName").isFile()) { return false } // If it is not the case we check whether it was downloaded by ReactAndroid project if (file("$reactNativeAndroidDownloadDir/$artifactLocalName").isFile()) { return true } return false } } } /* Reanimated includes "hermes/hermes.h" header file in `NativeProxy.cpp`. Previously, we used header files from `hermes-engine` package in `node_modules`. In React Native 0.69 and 0.70, 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_MINOR_VERSION in [69, 70] && !IS_NEW_ARCHITECTURE_ENABLED) { // copied from `react-native/ReactAndroid/hermes-engine/build.gradle` def downloadDir = customDownloadsDir ? new File(customDownloadsDir) : new File(reactNativeRootDir, "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(reactNativeRootDir, "sdks/hermes") def hermesVersion = "main" def hermesVersionFile = new File(reactNativeRootDir, "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-` // folder at the top level. if (file.relativePath.segments.size() > 1) { file.relativePath = new RelativePath(!file.isDirectory(), file.relativePath.segments.drop(1)) } } } into(hermesDir) } } if (REACT_NATIVE_MINOR_VERSION < 71) { // You need to have following folders in this directory: // - boost_1_63_0 // - double-conversion-1.1.6 // - folly-deprecate-dynamic-initializer // - glog-0.3.5 def dependenciesPath = System.getenv("REACT_NATIVE_DEPENDENCIES") // The Boost library is a very large download (>100MB). // If Boost is already present on your system, define the REACT_NATIVE_BOOST_PATH env variable // and the build will use that. def boostPath = dependenciesPath ?: System.getenv("REACT_NATIVE_BOOST_PATH") def follyReplaceContent = ''' ssize_t r; do { r = open(name, flags, mode); } while (r == -1 && errno == EINTR); return r; ''' Task resolveBoost = resolveTaskFactory("resolveBoost", "boost_${BOOST_VERSION}.tar.gz", reactNativeAndroidDownloadDir, downloadsDir) Task resolveDoubleConversion = resolveTaskFactory( "resolveDoubleConversion", "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz", reactNativeAndroidDownloadDir, downloadsDir ) Task resolveFolly = resolveTaskFactory("resolveFolly", "folly-${FOLLY_VERSION}.tar.gz", reactNativeAndroidDownloadDir, downloadsDir) Task resolveGlog = resolveTaskFactory("resolveGlog", "glog-${GLOG_VERSION}.tar.gz", reactNativeAndroidDownloadDir, downloadsDir) if (IS_NEW_ARCHITECTURE_ENABLED) { def reactNativeAndroidProject = findProject(":ReactAndroid") if (reactNativeAndroidProject != null) { reactNativeAndroidProject.afterEvaluate { def resolveTasks = [resolveBoost, resolveGlog, resolveDoubleConversion, resolveFolly] resolveTasks.forEach({ task -> String reactAndroidDownloadTaskName = "download" + task.name.replace("resolve", "") def reactAndroidDownloadTask = reactNativeAndroidProject.getTasks().findByName(reactAndroidDownloadTaskName) if (reactAndroidDownloadTask != null) { task.dependsOn(reactAndroidDownloadTask) } else { logger.warn("[Reanimated] Failed to find task named `$reactAndroidDownloadTaskName` in `:ReactAndroid` project." + " Explicit dependency between it and $task.name task can not be set.") } }) } } else { throw new GradleException("[Reanimated] Failed to find `:ReactAndroid` project. Explicit dependency between download tasks can not be set.") } } task downloadBoost(dependsOn: resolveBoost, type: Download) { def transformedVersion = BOOST_VERSION.replace("_", ".") def artifactLocalName = "boost_${BOOST_VERSION}.tar.gz" def srcUrl = "https://archives.boost.io/release/${transformedVersion}/source/${artifactLocalName}" if (REACT_NATIVE_MINOR_VERSION < 69) { srcUrl = "https://github.com/react-native-community/boost-for-react-native/releases/download/v${transformedVersion}-0/${artifactLocalName}" } src(srcUrl) onlyIfNewer(true) overwrite(false) dest(new File(downloadsDir, artifactLocalName)) } task prepareBoost(dependsOn: boostPath ? [] : [downloadBoost], type: Copy) { from(boostPath ?: tarTree(resources.gzip(downloadBoost.dest))) from("$reactNativeThirdParty/boost/Android.mk") include("Android.mk", "boost_${BOOST_VERSION}/boost/**/*.hpp", "boost/boost/**/*.hpp") includeEmptyDirs = false into("$thirdPartyNdkDir/boost") doLast { file("$thirdPartyNdkDir/boost/boost").renameTo("$thirdPartyNdkDir/boost/boost_${BOOST_VERSION}") } } task downloadDoubleConversion(dependsOn: resolveDoubleConversion, type: Download) { src("https://github.com/google/double-conversion/archive/v${DOUBLE_CONVERSION_VERSION}.tar.gz") onlyIfNewer(true) overwrite(false) dest(new File(downloadsDir, "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz")) } task prepareDoubleConversion(dependsOn: dependenciesPath ? [] : [downloadDoubleConversion], type: Copy) { from(dependenciesPath ?: tarTree(downloadDoubleConversion.dest)) from("$reactNativeThirdParty/double-conversion/Android.mk") include("double-conversion-${DOUBLE_CONVERSION_VERSION}/src/**/*", "Android.mk") filesMatching("*/src/**/*", { fname -> fname.path = "double-conversion/${fname.name}" }) includeEmptyDirs = false into("$thirdPartyNdkDir/double-conversion") } task downloadFolly(dependsOn: resolveFolly, type: Download) { src("https://github.com/facebook/folly/archive/v${FOLLY_VERSION}.tar.gz") onlyIfNewer(true) overwrite(false) dest(new File(downloadsDir, "folly-${FOLLY_VERSION}.tar.gz")) } task prepareFolly(dependsOn: dependenciesPath ? [] : [downloadFolly], type: Copy) { from(dependenciesPath ?: tarTree(downloadFolly.dest)) from("$reactNativeThirdParty/folly/Android.mk") include("folly-${FOLLY_VERSION}/folly/**/*", "Android.mk") eachFile { fname -> fname.path = (fname.path - "folly-${FOLLY_VERSION}/") } // Fixes problem with Folly failing to build on certain systems. See // https://github.com/software-mansion/react-native-reanimated/issues/1024 filter { line -> line.replaceAll("return int\\(wrapNoInt\\(open, name, flags, mode\\)\\);", follyReplaceContent) } includeEmptyDirs = false into("$thirdPartyNdkDir/folly") } task downloadGlog(dependsOn: resolveGlog, type: Download) { src("https://github.com/google/glog/archive/v${GLOG_VERSION}.tar.gz") onlyIfNewer(true) overwrite(false) dest(new File(downloadsDir, "glog-${GLOG_VERSION}.tar.gz")) } // Prepare glog sources to be compiled, this task will perform steps that normally should've been // executed by automake. This way we can avoid dependencies on make/automake task prepareGlog(dependsOn: dependenciesPath ? [] : [downloadGlog], type: Copy) { duplicatesStrategy = "include" from(dependenciesPath ?: tarTree(downloadGlog.dest)) from("$reactNativeThirdParty/glog/") include("glog-${GLOG_VERSION}/src/**/*", "Android.mk", "config.h") includeEmptyDirs = false filesMatching("**/*.h.in") { filter(ReplaceTokens, tokens: [ ac_cv_have_unistd_h : "1", ac_cv_have_stdint_h : "1", ac_cv_have_systypes_h : "1", ac_cv_have_inttypes_h : "1", ac_cv_have_libgflags : "0", ac_google_start_namespace : "namespace google {", ac_cv_have_uint16_t : "1", ac_cv_have_u_int16_t : "1", ac_cv_have___uint16 : "0", ac_google_end_namespace : "}", ac_cv_have___builtin_expect : "1", ac_google_namespace : "google", ac_cv___attribute___noinline : "__attribute__ ((noinline))", ac_cv___attribute___noreturn : "__attribute__ ((noreturn))", ac_cv___attribute___printf_4_5: "__attribute__((__format__ (__printf__, 4, 5)))" ]) it.path = (it.name - ".in") } into("$thirdPartyNdkDir/glog") doLast { copy { from(fileTree(dir: "$thirdPartyNdkDir/glog", includes: ["stl_logging.h", "logging.h", "raw_logging.h", "vlog_is_on.h", "**/src/glog/log_severity.h"]).files) includeEmptyDirs = false into("$thirdPartyNdkDir/glog/exported/glog") } } } task prepareHermes { if (REACT_NATIVE_MINOR_VERSION >= 69) { if (!IS_NEW_ARCHITECTURE_ENABLED) { dependsOn(unzipHermes) } doLast { // e.g. hermes-engine-0.70.0-rc.1-debug.aar def hermesAAR = file( "$reactNativeRootDir/android/com/facebook/react/hermes-engine/" + "${REACT_NATIVE_VERSION}/hermes-engine-${REACT_NATIVE_VERSION}-" + "${resolveBuildType()}.aar" ) if (!hermesAAR.exists()) { throw new GradleException("[Reanimated] Could not find hermes-engine AAR.", null) } def soFiles = zipTree(hermesAAR).matching({ it.include "**/*.so" }) copy { from soFiles from "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/hermes/Android.mk" into "$thirdPartyNdkDir/hermes" } } } else { doLast { def hermesPackagePath = findNodeModulePath(projectDir, "hermes-engine") if (!hermesPackagePath) { throw new GradleException("[Reanimated] Could not find the hermes-engine npm package.", null) } def hermesAAR = file("$hermesPackagePath/android/hermes-${resolveBuildType()}.aar") // e.g. hermes-debug.aar if (!hermesAAR.exists()) { throw new GradleException("[Reanimated] The hermes-engine npm package is missing \"android/hermes-${resolveBuildType()}.aar\".", null) } def soFiles = zipTree(hermesAAR).matching({ it.include "**/*.so" }) copy { from soFiles from "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/hermes/Android.mk" into "$thirdPartyNdkDir/hermes" } } } } task prepareJSC { if (REACT_NATIVE_MINOR_VERSION >= 71) { // do nothing } else { doLast { def jscPackagePath = findNodeModulePath(projectDir, "jsc-android") if (!jscPackagePath) { throw new GradleException("[Reanimated] Could not find the jsc-android npm package.", null) } def jscDist = file("$jscPackagePath/dist") if (!jscDist.exists()) { throw new GradleException("[Reanimated] The jsc-android npm package is missing its \"dist\" directory.", null) } def jscAAR = fileTree(jscDist).matching({ it.include "**/android-jsc/**/*.aar" }).singleFile def soFiles = zipTree(jscAAR).matching({ it.include "**/*.so" }) def headerFiles = fileTree(jscDist).matching({ it.include "**/include/*.h" }) copy { from(soFiles) from(headerFiles) from("$reactNativeRootDir/ReactAndroid/src/main/jni/third-party/jsc/Android.mk") filesMatching("**/*.h", { it.path = "JavaScriptCore/${it.name}" }) includeEmptyDirs(false) into("$thirdPartyNdkDir/jsc") } } } } task extractAARHeaders { doLast { configurations.extractHeaders.files.each { def file = it.absoluteFile def packageName = file.name.tokenize('-')[0] copy { from zipTree(file) into "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/$packageName/headers" include "**/*.h" } } } } task extractSOFiles { doLast { configurations.extractSO.files.each { def file = it.absoluteFile def packageName = file.name.tokenize('-')[0] copy { from zipTree(file) into "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/$packageName/" include "jni/**/*.so" } } } } task unpackReactNativeAAR { def buildType = resolveBuildType() def rnAarMatcher = "**/react-native/**/*${buildType}.aar" if (REACT_NATIVE_MINOR_VERSION < 69) { rnAarMatcher = "**/**/*.aar" } def rnAAR = fileTree("$reactNativeRootDir/android").matching({ it.include rnAarMatcher }).singleFile def file = rnAAR.absoluteFile def packageName = file.name.tokenize('-')[0] copy { from zipTree(file) into "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/$packageName/" include "jni/**/*.so" } } task downloadNdkBuildDependencies { if (!boostPath) { dependsOn(downloadBoost) } dependsOn(downloadDoubleConversion) dependsOn(downloadFolly) dependsOn(downloadGlog) } task prepareThirdPartyNdkHeaders(dependsOn:[ downloadNdkBuildDependencies, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog, unpackReactNativeAAR] ) {} } task packageNdkLibs(type: Copy) { from("$buildDir/reanimated-ndk/all") include("**/libreanimated.so") into("$projectDir/src/main/jniLibs") } repositories { mavenCentral() mavenLocal() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url "$reactNativeRootDir/android" } maven { // Android JSC is installed from npm url "$reactNativeRootDir/../jsc-android/dist" } google() } dependencies { implementation "com.facebook.yoga:proguard-annotations:1.19.0" implementation "androidx.transition:transition:1.1.0" implementation "androidx.core:core:1.6.0" if (REACT_NATIVE_MINOR_VERSION >= 71) { implementation "com.facebook.react:react-android" // version substituted by RNGP if (JS_RUNTIME == "hermes") { implementation "com.facebook.react:hermes-android" // version substituted by RNGP } } else { // noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" // From node_modules implementation "com.facebook.fbjni:fbjni-java-only:" + FBJNI_VERSION extractHeaders("com.facebook.fbjni:fbjni:" + FBJNI_VERSION + ":headers") extractSO("com.facebook.fbjni:fbjni:" + FBJNI_VERSION) def jscAAR = fileTree("$reactNativeRootDir/../jsc-android/dist/org/webkit/android-jsc").matching({ it.include "**/**/*.aar" }).singleFile extractSO(files(jscAAR)) } } def nativeBuildDependsOn(dependsOnTask) { def buildTasks = tasks.findAll({ task -> ( !task.name.contains("Clean") && (task.name.contains("externalNative") || task.name.contains("CMake") || task.name.contains("generateJsonModel") ) ) }) buildTasks.forEach { task -> task.dependsOn(dependsOnTask) } } afterEvaluate { if (REACT_NATIVE_MINOR_VERSION < 71) { extractAARHeaders.dependsOn(prepareThirdPartyNdkHeaders) extractSOFiles.dependsOn(prepareThirdPartyNdkHeaders) nativeBuildDependsOn(prepareThirdPartyNdkHeaders) nativeBuildDependsOn(extractAARHeaders) nativeBuildDependsOn(extractSOFiles) } preBuild.dependsOn(prepareHeadersForPrefab) tasks.forEach({ task -> if (task.name.contains("JniLibFolders")) { task.dependsOn(packageNdkLibs) } }) if (JS_RUNTIME == "hermes") { if (REACT_NATIVE_MINOR_VERSION < 71) { extractAARHeaders.dependsOn(prepareHermes) extractSOFiles.dependsOn(prepareHermes) } } else if (JS_RUNTIME == "v8") { def buildTasks = tasks.findAll({ task -> !task.name.contains("Clean") && (task.name.contains("externalNative") || task.name.contains("CMake") || task.name.startsWith("generateJsonModel")) }) buildTasks.forEach { task -> def buildType = task.name.endsWith('Debug') ? 'Debug' : 'Release' task.dependsOn(":react-native-v8:copy${buildType}JniLibsProjectOnly") } } else if (JS_RUNTIME == "jsc") { if (REACT_NATIVE_MINOR_VERSION < 71) { extractAARHeaders.dependsOn(prepareJSC) extractSOFiles.dependsOn(prepareJSC) } } else { throw GradleScriptException("[Reanimated] Unknown JS runtime ${JS_RUNTIME}.") } }