From c96c76eb9107ea92ff6dc2dcec114f3bd57102bd Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 25 Oct 2022 13:13:14 -0700 Subject: [PATCH] Update the template to use RNGP (#35075) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/35075 This diff updates the New App template for Android to use the React Native Gradle Plugin. With this we can: 1. Get rid of all the C++ code. 2. Remove a lot of New Architecture logic in the build.gradle 3. Reuse the prebuilts of React Native/Hermes via prefab Changelog: [Android] [Changed] - Update the template to use RNGP Reviewed By: cipolleschi Differential Revision: D40673732 fbshipit-source-id: 70935248993d1e24904c982e75f12ad580faa9d8 --- .circleci/config.yml | 13 +- ReactAndroid/publish.gradle | 5 + build.gradle.kts | 10 +- package.json | 2 +- .../react-native-gradle-plugin/package.json | 2 +- .../react/utils/NdkConfiguratorUtils.kt | 137 ++++++++++-------- scripts/release-utils.js | 15 +- template/android/app/build.gradle | 71 +-------- .../android/app/src/main/jni/CMakeLists.txt | 7 - template/android/app/src/main/jni/OnLoad.cpp | 50 ------- template/android/build.gradle | 9 +- template/android/settings.gradle | 7 - yarn.lock | 5 - 13 files changed, 107 insertions(+), 226 deletions(-) delete mode 100644 template/android/app/src/main/jni/CMakeLists.txt delete mode 100644 template/android/app/src/main/jni/OnLoad.cpp diff --git a/.circleci/config.yml b/.circleci/config.yml index 49c899f1571d18..e45bc414d7d8f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -805,7 +805,9 @@ jobs: - run: name: Build the template application for << parameters.flavor >> with New Architecture set to << parameters.newarchitecture >>, and using the << parameters.jsengine>> JS engine. - command: cd /tmp/$PROJECT_NAME/android/ && ./gradlew assemble<< parameters.flavor >> -PnewArchEnabled=<< parameters.newarchitecture >> + command: | + cd /tmp/$PROJECT_NAME/android/ + ./gradlew assemble<< parameters.flavor >> -PnewArchEnabled=<< parameters.newarchitecture >> -PREACT_NATIVE_MAVEN_LOCAL_REPO=/root/react-native/maven-local # ------------------------- # JOBS: Test iOS Template @@ -1443,6 +1445,15 @@ jobs: command: zip -r /tmp/hermes-native-symbols.zip ~/react-native/ReactAndroid/hermes-engine/build/intermediates/cmake/ - store_artifacts: path: /tmp/hermes-native-symbols.zip + - run: + name: Zip Maven Artifacts from /tmp/maven-local + command: zip -r /tmp/maven-local.zip /tmp/maven-local + - store_artifacts: + path: /tmp/maven-local.zip + - persist_to_workspace: + root: /tmp + paths: + - maven-local # START: Commitlies # Provide a react-native package for this commit as a Circle CI release artifact. diff --git a/ReactAndroid/publish.gradle b/ReactAndroid/publish.gradle index b2f25b38cbc106..637a0074663be8 100644 --- a/ReactAndroid/publish.gradle +++ b/ReactAndroid/publish.gradle @@ -14,6 +14,7 @@ def signingPwd = findProperty("SIGNING_PWD") def reactAndroidProjectDir = project(':ReactAndroid').projectDir def androidOutputUrl = "file://${reactAndroidProjectDir}/../android" +def mavenTempLocalUrl = "file:///tmp/maven-local" publishing { publications { @@ -68,6 +69,10 @@ publishing { name = "npm" url = androidOutputUrl } + maven { + name = "mavenTempLocal" + url = mavenTempLocalUrl + } } if (signingKey && signingPwd) { diff --git a/build.gradle.kts b/build.gradle.kts index 10a5f82e65f9c0..44ad75737b158f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -115,11 +115,11 @@ tasks.register("publishAllInsideNpmPackage") { dependsOn(":ReactAndroid:hermes-engine:installArchives") } -tasks.register("publishAllToMavenLocal") { - description = "Publish all the artifacts to be available inside Maven Local." - dependsOn(":ReactAndroid:publishToMavenLocal") - dependsOn(":ReactAndroid:external-artifacts:publishToMavenLocal") - dependsOn(":ReactAndroid:hermes-engine:publishToMavenLocal") +tasks.register("publishAllToMavenTempLocal") { + description = "Publish all the artifacts to be available inside a Maven Local repository on /tmp." + dependsOn(":ReactAndroid:publishAllPublicationsToMavenTempLocalRepository") + // We don't publish the external-artifacts to Maven Local as CircleCI is using it via workspace. + dependsOn(":ReactAndroid:hermes-engine:publishAllPublicationsToMavenTempLocalRepository") } tasks.register("publishAllToSonatype") { diff --git a/package.json b/package.json index a56cc7d09200ae..4115a071bc472e 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "pretty-format": "^26.5.2", "promise": "^8.2.0", "react-devtools-core": "^4.26.1", - "react-native-gradle-plugin": "0.71.4", + "react-native-gradle-plugin": "^0.71.6", "react-refresh": "^0.4.0", "react-shallow-renderer": "^16.15.0", "regenerator-runtime": "^0.13.2", diff --git a/packages/react-native-gradle-plugin/package.json b/packages/react-native-gradle-plugin/package.json index 1c2e37efa949bd..89f4f18111bdbc 100644 --- a/packages/react-native-gradle-plugin/package.json +++ b/packages/react-native-gradle-plugin/package.json @@ -1,6 +1,6 @@ { "name": "react-native-gradle-plugin", - "version": "0.71.5", + "version": "0.71.6", "description": "⚛️ Gradle Plugin for React Native", "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-gradle-plugin", "repository": { diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt index df09d4efcd35fa..9bec0e3bc2a9c2 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt @@ -16,75 +16,84 @@ import org.gradle.api.Project internal object NdkConfiguratorUtils { @Suppress("UnstableApiUsage") fun configureReactNativeNdk(project: Project, extension: ReactExtension) { - if (!project.isNewArchEnabled) { - return - } project.pluginManager.withPlugin("com.android.application") { project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext -> - // We enable prefab so users can consume .so/headers from ReactAndroid and hermes-engine - // .aar - ext.buildFeatures.prefab = true + if (!project.isNewArchEnabled) { + // For Old Arch, we set a pickFirst only on libraries that we know are + // clashing with our direct dependencies (FBJNI, Flipper and Hermes). + ext.packagingOptions.jniLibs.pickFirsts.addAll( + listOf( + "**/libfbjni.so", + "**/libc++_shared.so", + )) + } else { + // We enable prefab so users can consume .so/headers from ReactAndroid and hermes-engine + // .aar + ext.buildFeatures.prefab = true - // We set some packagingOptions { pickFirst ... } for our users for libraries we own. - ext.packagingOptions.jniLibs.pickFirsts.addAll( - listOf( - // Hermes & JSC are provided by AAR dependencies we pre-bundle. - "**/libhermes.so", - "**/libjsc.so", - // This is the .so provided by FBJNI via prefab - "**/libfbjni.so", - // Those are prefab libraries we distribute via ReactAndroid - // Due to a bug in AGP, they fire a warning on console as both the JNI - // and the prefab .so files gets considered. See more on: - "**/libfabricjni.so", - "**/libfolly_runtime.so", - "**/libglog.so", - "**/libjsi.so", - "**/libreact_codegen_rncore.so", - "**/libreact_debug.so", - "**/libreact_nativemodule_core.so", - "**/libreact_newarchdefaults.so", - "**/libreact_render_componentregistry.so", - "**/libreact_render_core.so", - "**/libreact_render_debug.so", - "**/libreact_render_graphics.so", - "**/libreact_render_mapbuffer.so", - "**/librrc_view.so", - "**/libruntimeexecutor.so", - "**/libturbomodulejsijni.so", - "**/libyoga.so", - // AGP will give priority of libc++_shared coming from App modules. - "**/libc++_shared.so", - )) + // We set some packagingOptions { pickFirst ... } for our users for libraries we own. + ext.packagingOptions.jniLibs.pickFirsts.addAll( + listOf( + // Hermes & JSC are provided by AAR dependencies we pre-bundle. + "**/libhermes.so", + "**/libjsc.so", + // This is the .so provided by FBJNI via prefab + "**/libfbjni.so", + // Those are prefab libraries we distribute via ReactAndroid + // Due to a bug in AGP, they fire a warning on console as both the JNI + // and the prefab .so files gets considered. See more on: + "**/libfabricjni.so", + "**/libfolly_runtime.so", + "**/libglog.so", + "**/libjsi.so", + "**/libreact_codegen_rncore.so", + "**/libreact_debug.so", + "**/libreact_nativemodule_core.so", + "**/libreact_newarchdefaults.so", + "**/libreact_render_componentregistry.so", + "**/libreact_render_core.so", + "**/libreact_render_debug.so", + "**/libreact_render_graphics.so", + "**/libreact_render_imagemanager.so", + "**/libreact_render_mapbuffer.so", + "**/librrc_image.so", + "**/librrc_view.so", + "**/libruntimeexecutor.so", + "**/libturbomodulejsijni.so", + "**/libyoga.so", + // AGP will give priority of libc++_shared coming from App modules. + "**/libc++_shared.so", + )) - // If the user has not provided a CmakeLists.txt path, let's provide - // the default one from the framework - if (ext.externalNativeBuild.cmake.path == null) { - ext.externalNativeBuild.cmake.path = - File( - extension.reactNativeDir.get().asFile, - "cmake-utils/default-app-setup/CMakeLists.txt") - } + // If the user has not provided a CmakeLists.txt path, let's provide + // the default one from the framework + if (ext.externalNativeBuild.cmake.path == null) { + ext.externalNativeBuild.cmake.path = + File( + extension.reactNativeDir.get().asFile, + "ReactAndroid/cmake-utils/default-app-setup/CMakeLists.txt") + } - // Parameters should be provided in an additive manner (do not override what - // the user provided, but allow for sensible defaults). - val cmakeArgs = ext.defaultConfig.externalNativeBuild.cmake.arguments - if ("-DGENERATED_SRC_DIR" !in cmakeArgs) { - cmakeArgs.add("-DGENERATED_SRC_DIR=${File(project.buildDir, "generated/source")}") - } - if ("-DPROJECT_BUILD_DIR" !in cmakeArgs) { - cmakeArgs.add("-DPROJECT_BUILD_DIR=${project.buildDir}") - } - if ("-DREACT_ANDROID_DIR" !in cmakeArgs) { - cmakeArgs.add( - "-DREACT_ANDROID_DIR=${extension.reactNativeDir.file("ReactAndroid").get().asFile}") - } - if ("-DREACT_ANDROID_BUILD_DIR" !in cmakeArgs) { - cmakeArgs.add( - "-DREACT_ANDROID_BUILD_DIR=${extension.reactNativeDir.file("ReactAndroid/build").get().asFile}") - } - if ("-DANDROID_STL" !in cmakeArgs) { - cmakeArgs.add("-DANDROID_STL=c++_shared") + // Parameters should be provided in an additive manner (do not override what + // the user provided, but allow for sensible defaults). + val cmakeArgs = ext.defaultConfig.externalNativeBuild.cmake.arguments + if ("-DGENERATED_SRC_DIR" !in cmakeArgs) { + cmakeArgs.add("-DGENERATED_SRC_DIR=${File(project.buildDir, "generated/source")}") + } + if ("-DPROJECT_BUILD_DIR" !in cmakeArgs) { + cmakeArgs.add("-DPROJECT_BUILD_DIR=${project.buildDir}") + } + if ("-DREACT_ANDROID_DIR" !in cmakeArgs) { + cmakeArgs.add( + "-DREACT_ANDROID_DIR=${extension.reactNativeDir.file("ReactAndroid").get().asFile}") + } + if ("-DREACT_ANDROID_BUILD_DIR" !in cmakeArgs) { + cmakeArgs.add( + "-DREACT_ANDROID_BUILD_DIR=${extension.reactNativeDir.file("ReactAndroid/build").get().asFile}") + } + if ("-DANDROID_STL" !in cmakeArgs) { + cmakeArgs.add("-DANDROID_STL=c++_shared") + } } } } diff --git a/scripts/release-utils.js b/scripts/release-utils.js index f095530a957c93..801afc93852f9d 100644 --- a/scripts/release-utils.js +++ b/scripts/release-utils.js @@ -33,15 +33,8 @@ function saveFilesToRestore(tmpPublishingFolder) { function generateAndroidArtifacts(releaseVersion, tmpPublishingFolder) { // -------- Generating Android Artifacts - env.REACT_NATIVE_SKIP_PREFAB = true; - if (exec('./gradlew :ReactAndroid:installArchives').code) { - echo('Could not generate artifacts'); - exit(1); - } - - // -------- Generating the Hermes Engine Artifacts - env.REACT_NATIVE_HERMES_SKIP_PREFAB = true; - if (exec('./gradlew :ReactAndroid:hermes-engine:installArchives').code) { + echo('Generating Android artifacts inside /tmp/maven-local'); + if (exec('./gradlew publishAllToMavenTempLocal').code) { echo('Could not generate artifacts'); exit(1); } @@ -63,12 +56,12 @@ function generateAndroidArtifacts(releaseVersion, tmpPublishingFolder) { if ( !test( '-e', - `./android/com/facebook/react/react-native/${releaseVersion}/${name}`, + `/tmp/maven-local/com/facebook/react/react-native/${releaseVersion}/${name}`, ) ) { echo( `Failing as expected file: \n\ - android/com/facebook/react/react-native/${releaseVersion}/${name}\n\ + /tmp/maven-local/com/facebook/react/react-native/${releaseVersion}/${name}\n\ was not correctly generated.`, ); exit(1); diff --git a/template/android/app/build.gradle b/template/android/app/build.gradle index 3a23b468c2d9f4..1a56feaba4970a 100644 --- a/template/android/app/build.gradle +++ b/template/android/app/build.gradle @@ -1,7 +1,7 @@ apply plugin: "com.android.application" +apply plugin: "com.facebook.react" import com.android.build.OutputFile -import org.apache.tools.ant.taskdefs.condition.Os /** * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets @@ -82,8 +82,6 @@ project.ext.react = [ enableHermes: true, // clean and rebuild if changing ] -apply from: "../../node_modules/react-native/react.gradle" - /** * Set this to true to create two separate APKs instead of one: * - An APK that only works on ARM devices @@ -140,40 +138,6 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" - buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() - - if (isNewArchitectureEnabled()) { - // We configure the CMake build only if you decide to opt-in for the New Architecture. - externalNativeBuild { - cmake { - arguments "-DPROJECT_BUILD_DIR=$buildDir", - "-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", - "-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build", - "-DANDROID_STL=c++_shared" - } - } - if (!enableSeparateBuildPerCPUArchitecture) { - ndk { - abiFilters (*reactNativeArchitectures()) - } - } - } - } - - if (isNewArchitectureEnabled()) { - // We configure the CMake build only if you decide to opt-in for the New Architecture. - externalNativeBuild { - cmake { - path "$projectDir/src/main/jni/CMakeLists.txt" - } - } - buildFeatures { - prefab true - } - } - packagingOptions { - pickFirst '**/libc++_shared.so' - pickFirst '**/libfbjni.so' } splits { @@ -225,10 +189,10 @@ android { dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) - //noinspection GradleDynamicVersion - implementation "com.facebook.react:react-native:+" // From node_modules + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-native") - implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" + implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { @@ -237,35 +201,10 @@ dependencies { debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") if (enableHermes) { - //noinspection GradleDynamicVersion - implementation("com.facebook.react:hermes-engine:+") // From node_modules + implementation("com.facebook.react:hermes-engine") } else { implementation jscFlavor } } -if (isNewArchitectureEnabled()) { - // If new architecture is enabled, we let you build RN from source - // Otherwise we fallback to a prebuilt .aar bundled in the NPM package. - // This will be applied to all the imported transitive dependency. - configurations.all { - resolutionStrategy.dependencySubstitution { - substitute(module("com.facebook.react:react-native")) - .using(project(":ReactAndroid")) - .because("On New Architecture we're building React Native from source") - substitute(module("com.facebook.react:hermes-engine")) - .using(project(":ReactAndroid:hermes-engine")) - .because("On New Architecture we're building Hermes from source") - } - } -} - apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) - -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" -} diff --git a/template/android/app/src/main/jni/CMakeLists.txt b/template/android/app/src/main/jni/CMakeLists.txt deleted file mode 100644 index 25c9c208afbcd4..00000000000000 --- a/template/android/app/src/main/jni/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required(VERSION 3.13) - -# Define the library name here. -project(appmodules) - -# This file includes all the necessary to let you build your application with the New Architecture. -include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) diff --git a/template/android/app/src/main/jni/OnLoad.cpp b/template/android/app/src/main/jni/OnLoad.cpp deleted file mode 100644 index 117fad7d6454a6..00000000000000 --- a/template/android/app/src/main/jni/OnLoad.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include -#include -#include - -namespace facebook { -namespace react { - -void registerComponents( - std::shared_ptr registry) { - // Custom Fabric Components go here. You can register custom - // components coming from your App or from 3rd party libraries here. - // - // providerRegistry->add(concreteComponentDescriptorProvider< - // AocViewerComponentDescriptor>()); - - // By default we just use the components autolinked by RN CLI - rncli_registerProviders(registry); -} - -std::shared_ptr provideModules( - const std::string &name, - const JavaTurboModule::InitParams ¶ms) { - // Here you can provide your own module provider for TurboModules coming from - // either your application or from external libraries. The approach to follow - // is similar to the following (for a library called `samplelibrary`): - // - // auto module = samplelibrary_ModuleProvider(moduleName, params); - // if (module != nullptr) { - // return module; - // } - // return rncore_ModuleProvider(moduleName, params); - - // By default we just use the module providers autolinked by RN CLI - return rncli_ModuleProvider(name, params); -} - -} // namespace react -} // namespace facebook - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - return facebook::jni::initialize(vm, [] { - facebook::react::DefaultTurboModuleManagerDelegate:: - moduleProvidersFromEntryPoint = &facebook::react::provideModules; - facebook::react::DefaultComponentsRegistry:: - registerComponentDescriptorsFromEntryPoint = - &facebook::react::registerComponents; - }); -} diff --git a/template/android/build.gradle b/template/android/build.gradle index bfa9a2b429203b..a893c5e2e8f3c9 100644 --- a/template/android/build.gradle +++ b/template/android/build.gradle @@ -17,7 +17,6 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:7.3.0") classpath("com.facebook.react:react-native-gradle-plugin") - classpath("de.undercouch:gradle-download-task:5.0.1") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -33,13 +32,7 @@ allprojects { // Android JSC is installed from npm url("$rootDir/../node_modules/jsc-android/dist") } - mavenCentral { - // We don't want to fetch react-native from Maven Central as there are - // older versions over there. - content { - excludeGroup "com.facebook.react" - } - } + mavenCentral() google() maven { url 'https://www.jitpack.io' } } diff --git a/template/android/settings.gradle b/template/android/settings.gradle index bd838b9c306d59..ab284c3a6bd22f 100644 --- a/template/android/settings.gradle +++ b/template/android/settings.gradle @@ -2,10 +2,3 @@ rootProject.name = 'HelloWorld' apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' includeBuild('../node_modules/react-native-gradle-plugin') - -if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { - include(":ReactAndroid") - project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') - include(":ReactAndroid:hermes-engine") - project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') -} diff --git a/yarn.lock b/yarn.lock index 5173fb435f26bc..740f4c15920f8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7960,11 +7960,6 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-native-gradle-plugin@0.71.4: - version "0.71.4" - resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.4.tgz#dd000c1539e0ce465237637d3e16fe619cd84467" - integrity sha512-5izzWXIlr5DL5+cx3a6oSA4cgSCw9Kv7WQjHqLxV2I1fSfzjzEdYTaDfrNjdcy71BHeeUB6BEyl70yXpjkCkdA== - react-refresh@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.4.0.tgz#d421f9bd65e0e4b9822a399f14ac56bda9c92292"