123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- /*
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
- plugins {
- id("com.android.library")
- id("maven")
- id("de.undercouch.download")
- }
- import java.nio.file.Paths
- import de.undercouch.gradle.tasks.download.Download
- import org.apache.tools.ant.taskdefs.condition.Os
- import org.apache.tools.ant.filters.ReplaceTokens
- // 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")
- // 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")
- // Setup build type for NDK, supported values: {debug, release}
- def nativeBuildType = System.getenv("NATIVE_BUILD_TYPE") ?: "release"
- task createNativeDepsDirectories {
- downloadsDir.mkdirs()
- thirdPartyNdkDir.mkdirs()
- }
- 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")
- onlyIfNewer(true)
- overwrite(false)
- dest(new File(downloadsDir, "boost_${BOOST_VERSION}.tar.gz"))
- }
- task prepareBoost(dependsOn: boostPath ? [] : [downloadBoost], type: Copy) {
- from(boostPath ?: tarTree(resources.gzip(downloadBoost.dest)))
- from("src/main/jni/third-party/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: createNativeDepsDirectories, 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("src/main/jni/third-party/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: createNativeDepsDirectories, 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("src/main/jni/third-party/folly/Android.mk")
- include("folly-${FOLLY_VERSION}/folly/**/*", "Android.mk")
- eachFile { fname -> fname.path = (fname.path - "folly-${FOLLY_VERSION}/") }
- includeEmptyDirs = false
- into("$thirdPartyNdkDir/folly")
- }
- task prepareHermes() {
- def hermesPackagePath = findNodeModulePath(projectDir, "hermes-engine")
- if (!hermesPackagePath) {
- throw new GradleScriptException("Could not find the hermes-engine npm package")
- }
- 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\"")
- }
- def soFiles = zipTree(hermesAAR).matching({ it.include "**/*.so" })
- copy {
- from soFiles
- from "src/main/jni/first-party/hermes/Android.mk"
- into "$thirdPartyNdkDir/hermes"
- }
- }
- task downloadGlog(dependsOn: createNativeDepsDirectories, 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) {
- from(dependenciesPath ?: tarTree(downloadGlog.dest))
- from("src/main/jni/third-party/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")
- }
- }
- }
- // Create Android.mk library module based on jsc from npm
- task prepareJSC {
- doLast {
- def jscPackagePath = findNodeModulePath(projectDir, "jsc-android")
- if (!jscPackagePath) {
- throw new GradleScriptException("Could not find the jsc-android npm package")
- }
- def jscDist = file("$jscPackagePath/dist")
- if (!jscDist.exists()) {
- throw new GradleScriptException("The jsc-android npm package is missing its \"dist\" directory")
- }
- 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("src/main/jni/third-party/jsc/Android.mk")
- filesMatching("**/*.h", { it.path = "JavaScriptCore/${it.name}" })
- includeEmptyDirs(false)
- into("$thirdPartyNdkDir/jsc")
- }
- }
- }
- task downloadNdkBuildDependencies {
- if (!boostPath) {
- dependsOn(downloadBoost)
- }
- dependsOn(downloadDoubleConversion)
- dependsOn(downloadFolly)
- dependsOn(downloadGlog)
- }
- /**
- * 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.
- */
- 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 getNdkBuildName() {
- if (Os.isFamily(Os.FAMILY_WINDOWS)) {
- return "ndk-build.cmd"
- } else {
- return "ndk-build"
- }
- }
- def findNdkBuildFullPath() {
- // we allow to provide full path to ndk-build tool
- if (hasProperty("ndk.command")) {
- return property("ndk.command")
- }
- // or just a path to the containing directory
- if (hasProperty("ndk.path")) {
- def ndkDir = property("ndk.path")
- return new File(ndkDir, getNdkBuildName()).getAbsolutePath()
- }
- if (System.getenv("ANDROID_NDK") != null) {
- def ndkDir = System.getenv("ANDROID_NDK")
- return new File(ndkDir, getNdkBuildName()).getAbsolutePath()
- }
- def ndkDir = android.ndkDirectory ? android.ndkDirectory.absolutePath : null
- if (ndkDir) {
- return new File(ndkDir, getNdkBuildName()).getAbsolutePath()
- }
- return null
- }
- def reactNativeDevServerPort() {
- def value = project.getProperties().get("reactNativeDevServerPort")
- return value != null ? value : "8081"
- }
- def reactNativeInspectorProxyPort() {
- def value = project.getProperties().get("reactNativeInspectorProxyPort")
- return value != null ? value : reactNativeDevServerPort()
- }
- def getNdkBuildFullPath() {
- def ndkBuildFullPath = findNdkBuildFullPath()
- if (ndkBuildFullPath == null) {
- throw new GradleScriptException(
- "ndk-build binary cannot be found, check if you've set " +
- "\$ANDROID_NDK environment variable correctly or if ndk.dir is " +
- "setup in local.properties",
- null)
- }
- if (!new File(ndkBuildFullPath).canExecute()) {
- throw new GradleScriptException(
- "ndk-build binary " + ndkBuildFullPath + " doesn't exist or isn't executable.\n" +
- "Check that the \$ANDROID_NDK environment variable, or ndk.dir in local.properties, is set correctly.\n" +
- "(On Windows, make sure you escape backslashes in local.properties or use forward slashes, e.g. C:\\\\ndk or C:/ndk rather than C:\\ndk)",
- null)
- }
- return ndkBuildFullPath
- }
- def buildReactNdkLib = tasks.register("buildReactNdkLib", Exec) {
- dependsOn(prepareJSC, prepareHermes, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog, extractAARHeaders, extractJNIFiles)
- inputs.dir("$projectDir/../ReactCommon")
- inputs.dir("src/main/jni")
- inputs.dir("src/main/java/com/facebook/react/modules/blob")
- outputs.dir("$buildDir/react-ndk/all")
- commandLine(getNdkBuildFullPath(),
- "NDK_DEBUG=" + (nativeBuildType.equalsIgnoreCase("debug") ? "1" : "0"),
- "NDK_PROJECT_PATH=null",
- "NDK_APPLICATION_MK=$projectDir/src/main/jni/Application.mk",
- "NDK_OUT=" + temporaryDir,
- "NDK_LIBS_OUT=$buildDir/react-ndk/all",
- "THIRD_PARTY_NDK_DIR=$buildDir/third-party-ndk",
- "REACT_COMMON_DIR=$projectDir/../ReactCommon",
- "REACT_SRC_DIR=$projectDir/src/main/java/com/facebook/react",
- "-C", file("src/main/jni/react/jni").absolutePath,
- "--jobs", project.findProperty("jobs") ?: Runtime.runtime.availableProcessors()
- )
- }
- def cleanReactNdkLib = tasks.register("cleanReactNdkLib", Exec) {
- ignoreExitValue(true)
- errorOutput(new ByteArrayOutputStream())
- commandLine(getNdkBuildFullPath(),
- "NDK_APPLICATION_MK=$projectDir/src/main/jni/Application.mk",
- "THIRD_PARTY_NDK_DIR=$buildDir/third-party-ndk",
- "REACT_COMMON_DIR=$projectDir/../ReactCommon",
- "-C", file("src/main/jni/react/jni").absolutePath,
- "clean")
- doLast {
- file(AAR_OUTPUT_URL).delete()
- println("Deleted aar output dir at ${file(AAR_OUTPUT_URL)}")
- }
- }
- def packageReactNdkLibs = tasks.register("packageReactNdkLibs", Copy) {
- dependsOn(buildReactNdkLib)
- from("$buildDir/react-ndk/all")
- into("$buildDir/react-ndk/exported")
- exclude("**/libjsc.so")
- exclude("**/libhermes.so")
- }
- def packageReactNdkLibsForBuck = tasks.register("packageReactNdkLibsForBuck", Copy) {
- dependsOn(packageReactNdkLibs)
- from("$buildDir/react-ndk/exported")
- into("src/main/jni/prebuilt/lib")
- }
- task extractAARHeaders {
- doLast {
- configurations.extractHeaders.files.each {
- def file = it.absoluteFile
- def packageName = file.name.tokenize('-')[0]
- copy {
- from zipTree(file)
- into "$projectDir/src/main/jni/first-party/$packageName/headers"
- include "**/*.h"
- }
- }
- }
- }
- task extractJNIFiles {
- doLast {
- configurations.extractJNI.files.each {
- def file = it.absoluteFile
- def packageName = file.name.tokenize('-')[0]
- copy {
- from zipTree(file)
- into "$projectDir/src/main/jni/first-party/$packageName/"
- include "jni/**/*"
- }
- }
- }
- }
- android {
- compileSdkVersion 29
- compileOptions {
- sourceCompatibility(JavaVersion.VERSION_1_8)
- targetCompatibility(JavaVersion.VERSION_1_8)
- }
- defaultConfig {
- minSdkVersion(16)
- targetSdkVersion(28)
- versionCode(1)
- versionName("1.0")
- consumerProguardFiles("proguard-rules.pro")
- ndk {
- moduleName("reactnativejni")
- }
- buildConfigField("boolean", "IS_INTERNAL_BUILD", "false")
- buildConfigField("int", "EXOPACKAGE_FLAGS", "0")
- resValue "integer", "react_native_dev_server_port", reactNativeDevServerPort()
- resValue "integer", "react_native_inspector_proxy_port", reactNativeInspectorProxyPort()
- testApplicationId("com.facebook.react.tests.gradle")
- testInstrumentationRunner("androidx.test.runner.AndroidJUnitRunner")
- }
- sourceSets.main {
- jni.srcDirs = []
- jniLibs.srcDir("$buildDir/react-ndk/exported")
- res.srcDirs = ["src/main/res/devsupport", "src/main/res/shell", "src/main/res/views/modal", "src/main/res/views/uimanager"]
- java {
- srcDirs = ["src/main/java", "src/main/libraries/soloader/java", "src/main/jni/first-party/fb/jni/java"]
- exclude("com/facebook/react/processing")
- exclude("com/facebook/react/module/processing")
- }
- }
- tasks.withType(JavaCompile) {
- compileTask ->
- compileTask.dependsOn(packageReactNdkLibs)
- }
- clean.dependsOn(cleanReactNdkLib)
- lintOptions {
- abortOnError(false)
- }
- packagingOptions {
- exclude("META-INF/NOTICE")
- exclude("META-INF/LICENSE")
- }
- configurations {
- extractHeaders
- extractJNI
- }
- }
- dependencies {
- api("com.facebook.infer.annotation:infer-annotation:0.11.2")
- api("com.facebook.yoga:proguard-annotations:1.14.1")
- api("javax.inject:javax.inject:1")
- api("androidx.appcompat:appcompat:1.0.2")
- api("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
- api("com.facebook.fresco:fresco:${FRESCO_VERSION}")
- api("com.facebook.fresco:imagepipeline-okhttp3:${FRESCO_VERSION}")
- api("com.facebook.soloader:soloader:${SO_LOADER_VERSION}")
- api("com.google.code.findbugs:jsr305:3.0.2")
- api("com.squareup.okhttp3:okhttp:${OKHTTP_VERSION}")
- api("com.squareup.okhttp3:okhttp-urlconnection:${OKHTTP_VERSION}")
- api("com.squareup.okio:okio:1.15.0")
- api("com.facebook.fbjni:fbjni-java-only:0.0.3")
- extractHeaders("com.facebook.fbjni:fbjni:0.0.2:headers")
- extractJNI("com.facebook.fbjni:fbjni:0.0.2")
- testImplementation("junit:junit:${JUNIT_VERSION}")
- testImplementation("org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}")
- testImplementation("org.powermock:powermock-module-junit4-rule:${POWERMOCK_VERSION}")
- testImplementation("org.powermock:powermock-classloading-xstream:${POWERMOCK_VERSION}")
- testImplementation("org.mockito:mockito-core:${MOCKITO_CORE_VERSION}")
- testImplementation("org.easytesting:fest-assert-core:${FEST_ASSERT_CORE_VERSION}")
- testImplementation("org.robolectric:robolectric:${ROBOLECTRIC_VERSION}")
- androidTestImplementation(fileTree(dir: "src/main/third-party/java/buck-android-support/", include: ["*.jar"]))
- androidTestImplementation("androidx.test:runner:${ANDROIDX_TEST_VERSION}")
- androidTestImplementation("androidx.test:rules:${ANDROIDX_TEST_VERSION}")
- androidTestImplementation("org.mockito:mockito-core:${MOCKITO_CORE_VERSION}")
- }
- apply(from: "release.gradle")
|