- App.tsx: full navigation (Auth stack + Main tabs with 5 screens) - Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen - HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors - MapScreen: interactive map with layer toggles (6 layers) - MarketplaceScreen: categories (6), products (5), search - ChatScreen: AI chat with quick prompts (4), bot responses - ProfileScreen: user info, stats, menu (9 items), logout - AlertsScreen: alert list with severity, acknowledge - SensorsScreen: sensor list with type filters (6 types), search - ZonesScreen: zone cards with stats - SettingsScreen: language picker (FR/EN/ES/DE), privacy, about - Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n - Hooks: useSensors, useAlerts, useNotifications, useLocation - Components: Card, Button, LoadingSpinner, ErrorBoundary, Header - Services: iotService, notificationService (with axios API client) - Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN) - Theme: colors.ts with full design system (Blue Ocean palette) - Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
922 lines
36 KiB
Groovy
922 lines
36 KiB
Groovy
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
|
|
}
|
|
|
|
if (isNewArchitectureEnabled()) {
|
|
apply plugin: "com.facebook.react"
|
|
}
|
|
|
|
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 <= 72) {
|
|
srcDirs += "src/reactNativeVersionPatch/messageQueueThread/72"
|
|
} else {
|
|
srcDirs += "src/reactNativeVersionPatch/messageQueueThread/latest"
|
|
}
|
|
}
|
|
|
|
// ReanimatedUIManager & ReanimatedUIImplementation
|
|
if (REACT_NATIVE_MINOR_VERSION <= 73) {
|
|
srcDirs += "src/reactNativeVersionPatch/ReanimatedUIManager/73"
|
|
} 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"
|
|
}
|
|
}
|
|
|
|
// RuntimeExecutor
|
|
if (IS_NEW_ARCHITECTURE_ENABLED) {
|
|
if (REACT_NATIVE_MINOR_VERSION <= 73) {
|
|
srcDirs += "src/reactNativeVersionPatch/RuntimeExecutor/73"
|
|
} else {
|
|
srcDirs += "src/reactNativeVersionPatch/RuntimeExecutor/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-<SHA>`
|
|
// 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}.")
|
|
}
|
|
}
|