From be72feb4b024968dfa86bf5b7db60c5b6ec59b70 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Thu, 27 Oct 2022 11:51:42 -0700 Subject: [PATCH] Cleanup the template documentation after RNGP & hermesEnabled to gradle.properties (#35108) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/35108 I've rewritten the comment in the android/app/build.gradle. They were really old, contained wrong links and most of the people ignored it. I've also moved the enabling of Hermes to the `gradle.properties` file. RNGP still supports the old method, but we must be sure that we notify library authors if they were reading project.ext.react.enableHermes in the past (also the website needs to be updated). I've also cleaned up the CircleCI setup as now we can specify Hermes enabled/disabled via the CLI (this will also make easier to do e2e testing). Changelog: [Android] [Changed] - Cleanup the template documentation after RNGP & hermesEnabled to gradle.properties Reviewed By: cipolleschi Differential Revision: D40762872 fbshipit-source-id: 58fd2c87b3460da21f2560d7beb93710b626cda5 --- .circleci/config.yml | 35 ++--- packages/rn-tester/android/app/build.gradle | 132 ++++++----------- scripts/set-rn-engine.js | 53 ------- template/android/app/build.gradle | 155 +++++++------------- template/android/build.gradle | 2 - template/android/gradle.properties | 4 + 6 files changed, 125 insertions(+), 256 deletions(-) delete mode 100755 scripts/set-rn-engine.js diff --git a/.circleci/config.yml b/.circleci/config.yml index b3ee733c859655..71f5f6d2017f58 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -760,9 +760,11 @@ jobs: description: The Android build type. Must be one of "Debug", "Release". type: enum enum: ["Debug", "Release"] - newarchitecture: - type: boolean - default: false + architecture: + default: "OldArch" + description: Which React Native architecture to use. Must be one of "NewArch", "OldArch". + type: enum + enum: [ "NewArch", "OldArch" ] jsengine: default: "Hermes" description: Which JavaScript engine to use. Must be one of "Hermes", "JSC". @@ -775,17 +777,6 @@ jobs: - run_yarn - attach_workspace: at: . - - when: - condition: - equal: ["JSC", << parameters.jsengine >>] - steps: - - run: - name: Set enableHermes in buld.gradle to false - command: | - node ./scripts/set-rn-engine.js -e jsc - echo "Hermes disabled." - grep enableHermes: template/android/app/build.gradle - - run: name: Create Android template project command: | @@ -796,10 +787,20 @@ jobs: yarn - run: - name: Build the template application for << parameters.flavor >> with New Architecture set to << parameters.newarchitecture >>, and using the << parameters.jsengine>> JS engine. + name: Build the template application for << parameters.flavor >> with Architecture set to << parameters.architecture >>, and using the << parameters.jsengine>> JS engine. command: | cd /tmp/$PROJECT_NAME/android/ - ./gradlew assemble<< parameters.flavor >> -PnewArchEnabled=<< parameters.newarchitecture >> -PREACT_NATIVE_MAVEN_LOCAL_REPO=/root/react-native/maven-local + if [[ << parameters.architecture >> == "NewArch" ]]; then + export ORG_GRADLE_PROJECT_newArchEnabled=true + else + export ORG_GRADLE_PROJECT_newArchEnabled=false + fi + if [[ << parameters.jsengine >> == "Hermes" ]]; then + export ORG_GRADLE_PROJECT_hermesEnabled=true + else + export ORG_GRADLE_PROJECT_hermesEnabled=false + fi + ./gradlew assemble<< parameters.flavor >> -PREACT_NATIVE_MAVEN_LOCAL_REPO=/root/react-native/maven-local # ------------------------- # JOBS: Test iOS Template @@ -1602,7 +1603,7 @@ workflows: - build_npm_package matrix: parameters: - newarchitecture: [true, false] + architecture: ["NewArch", "OldArch"] jsengine: ["Hermes", "JSC"] flavor: ["Debug", "Release"] - test_buck diff --git a/packages/rn-tester/android/app/build.gradle b/packages/rn-tester/android/app/build.gradle index 86d3646ba34ce8..c7d5c448d5bd29 100644 --- a/packages/rn-tester/android/app/build.gradle +++ b/packages/rn-tester/android/app/build.gradle @@ -11,92 +11,57 @@ plugins { } /** - * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets - * and bundleReleaseJsAndAssets). - * These basically call `react-native bundle` with the correct arguments during the Android build - * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the - * bundle directly from the development server. Below you can see all the possible configurations - * and their defaults. If you decide to add a configuration block, make sure to add it before the - * `apply from: "react.gradle"` line. - * - * project.ext.react = [ - * // the name of the generated asset file containing your JS bundle - * bundleAssetName: "index.android.bundle", - * - * // the entry file for bundle generation - * entryFile: "index.android.js", - * - * // whether to bundle JS and assets in debug mode - * bundleInDebug: false, - * - * // whether to bundle JS and assets in release mode - * bundleInRelease: true, - * - * // whether to bundle JS and assets in another build variant (if configured). - * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants - * // The configuration property is in the format 'bundleIn${productFlavor}${buildType}' - * // bundleInFreeDebug: true, - * // bundleInPaidRelease: true, - * // bundleInBeta: true, - * - * // the root of your project, i.e. where "package.json" lives - * root: "../../", - * - * // where to put the JS bundle asset in debug mode - * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", - * - * // where to put the JS bundle asset in release mode - * jsBundleDirRelease: "$buildDir/intermediates/assets/release", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in debug mode - * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in release mode - * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", - * - * // by default the gradle tasks are skipped if none of the JS files or assets change; this means - * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to - * // date; if you have any other folders that you want to ignore for performance reasons (gradle - * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ - * // for example, you might want to remove it from here. - * inputExcludes: ["android/**", "ios/**"], - * - * // Root dir for all JS files for the app. Defaults to `root` above. - * jsRootDir: "../..", - * - * // Enable Fabric at runtime. - * enableFabric: true, - * - * // Java package name to use for any codegen artifacts produced during build time. - * // Defaults to "com.facebook.fbreact.specs". - * codegenJavaPackageName: "com.facebook.fbreact.specs", - * ] + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. */ - react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '..' + root = file("../../") + // The folder where the react-native NPM package is. Default is ../node_modules/react-native + reactNativeDir = rootDir + // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen + codegenDir = file("$rootDir/node_modules/react-native-codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js cliFile = file("$rootDir/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + debuggableVariants = ["hermesDebug", "jscDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle bundleAssetName = "RNTesterApp.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' entryFile = file("../../js/RNTesterApp.android.js") - root = file("../../") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' hermesCommand = "$rootDir/ReactAndroid/hermes-engine/build/hermes/bin/hermesc" - debuggableVariants = ["hermesDebug", "jscDebug"] enableHermesOnlyInVariants = ["hermesDebug", "hermesRelease"] - - // Codegen Configs - reactNativeDir = rootDir - codegenDir = file("$rootDir/node_modules/react-native-codegen") } /** - * Set this to true to create three separate APKs instead of one: - * - A universal APK that works on all devices - * - An APK that only works on ARM devices - * - An APK that only works on x86 devices - * The advantage is the size of the APK is reduced by about 4MB. - * Upload all the APKs to the Play Store and people will download - * the correct one based on the CPU architecture of their device. + * Set this to true to create four separate APKs instead of one, + * one for each native architecture. This is useful if you don't + * use App Bundles (https://developer.android.com/guide/app-bundle/) + * and want to have separate APKs to upload to the Play Store. */ def enableSeparateBuildPerCPUArchitecture = true @@ -106,12 +71,11 @@ def enableSeparateBuildPerCPUArchitecture = true def enableProguardInReleaseBuilds = true /** - * Use the international variant of JavaScriptCore - * This variant includes the ICU i18n library to make APIs like `Date.toLocaleString` - * and `String.localeCompare` work when using with locales other than en-US. - * Note that this variant is about 6MiB larger per architecture than the default. + * The preferred build flavor of JavaScriptCore (JSC) + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` */ -def useIntlJsc = false +def jscFlavor = 'org.webkit:android-jsc:+' /** * Architectures to build native code for. @@ -206,11 +170,7 @@ dependencies { debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") - if (useIntlJsc) { - jscImplementation 'org.webkit:android-jsc-intl:+' - } else { - jscImplementation 'org.webkit:android-jsc:+' - } + jscImplementation jscFlavor androidTestImplementation 'junit:junit:4.12' } diff --git a/scripts/set-rn-engine.js b/scripts/set-rn-engine.js deleted file mode 100755 index 52afa5b749dfe8..00000000000000 --- a/scripts/set-rn-engine.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -/** - * This script updates the engine used by React Native - */ -const {echo, exec, exit, sed} = require('shelljs'); -const yargs = require('yargs'); - -let argv = yargs.option('e', { - alias: 'engine', - describe: 'Choose an engine', - type: 'string', - choices: ['hermes', 'jsc'], -}).argv; - -const engine = argv.engine; - -if (!engine) { - echo('You must specify an engine using -e'); - exit(1); -} - -// Change the template build.gradle -sed( - '-i', - /enableHermes:.*/, - engine === 'jsc' ? 'enableHermes: false' : 'enableHermes: true', - 'template/android/app/build.gradle', -); - -// Validate the hermes flag has been changed properly -const hermes = - exec( - 'grep enableHermes: template/android/app/build.gradle | awk \'{split($0,a,"[:,]"); print a[2]}\'', - {silent: true}, - ).stdout.trim() === 'true'; - -if ((engine === 'jsc' && hermes) || (engine === 'hermes' && !hermes)) { - echo('Failed to update the engine in template/android/app/build.gradle'); - echo('Fix the issue and try again'); - exit(1); -} - -exit(0); diff --git a/template/android/app/build.gradle b/template/android/app/build.gradle index 1a56feaba4970a..3ba40f561020c5 100644 --- a/template/android/app/build.gradle +++ b/template/android/app/build.gradle @@ -4,123 +4,84 @@ apply plugin: "com.facebook.react" import com.android.build.OutputFile /** - * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets - * and bundleReleaseJsAndAssets). - * These basically call `react-native bundle` with the correct arguments during the Android build - * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the - * bundle directly from the development server. Below you can see all the possible configurations - * and their defaults. If you decide to add a configuration block, make sure to add it before the - * `apply from: "../../node_modules/react-native/react.gradle"` line. - * - * project.ext.react = [ - * // the name of the generated asset file containing your JS bundle - * bundleAssetName: "index.android.bundle", - * - * // the entry file for bundle generation. If none specified and - * // "index.android.js" exists, it will be used. Otherwise "index.js" is - * // default. Can be overridden with ENTRY_FILE environment variable. - * entryFile: "index.android.js", - * - * // https://reactnative.dev/docs/performance#enable-the-ram-format - * bundleCommand: "ram-bundle", - * - * // whether to bundle JS and assets in debug mode - * bundleInDebug: false, - * - * // whether to bundle JS and assets in release mode - * bundleInRelease: true, - * - * // whether to bundle JS and assets in another build variant (if configured). - * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants - * // The configuration property can be in the following formats - * // 'bundleIn${productFlavor}${buildType}' - * // 'bundleIn${buildType}' - * // bundleInFreeDebug: true, - * // bundleInPaidRelease: true, - * // bundleInBeta: true, - * - * // whether to disable dev mode in custom build variants (by default only disabled in release) - * // for example: to disable dev mode in the staging build type (if configured) - * devDisabledInStaging: true, - * // The configuration property can be in the following formats - * // 'devDisabledIn${productFlavor}${buildType}' - * // 'devDisabledIn${buildType}' - * - * // the root of your project, i.e. where "package.json" lives - * root: "../../", - * - * // where to put the JS bundle asset in debug mode - * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", - * - * // where to put the JS bundle asset in release mode - * jsBundleDirRelease: "$buildDir/intermediates/assets/release", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in debug mode - * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in release mode - * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", - * - * // by default the gradle tasks are skipped if none of the JS files or assets change; this means - * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to - * // date; if you have any other folders that you want to ignore for performance reasons (gradle - * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ - * // for example, you might want to remove it from here. - * inputExcludes: ["android/**", "ios/**"], - * - * // override which node gets called and with what additional arguments - * nodeExecutableAndArgs: ["node"], - * - * // supply additional arguments to the packager - * extraPackagerArgs: [] - * ] + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. */ - -project.ext.react = [ - enableHermes: true, // clean and rebuild if changing -] +react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '..' + // root = file("../") + // The folder where the react-native NPM package is. Default is ../node_modules/react-native + // reactNativeDir = file("../node-modules/react-native") + // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen + // codegenDir = file("../node-modules/react-native-codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js + // cliFile = file("../node_modules/react-native/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] +} /** - * Set this to true to create two separate APKs instead of one: - * - An APK that only works on ARM devices - * - An APK that only works on x86 devices - * The advantage is the size of the APK is reduced by about 4MB. - * Upload all the APKs to the Play Store and people will download - * the correct one based on the CPU architecture of their device. + * Set this to true to create four separate APKs instead of one, + * one for each native architecture. This is useful if you don't + * use App Bundles (https://developer.android.com/guide/app-bundle/) + * and want to have separate APKs to upload to the Play Store. */ def enableSeparateBuildPerCPUArchitecture = false /** - * Run Proguard to shrink the Java bytecode in release builds. + * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ def enableProguardInReleaseBuilds = false /** - * The preferred build flavor of JavaScriptCore. + * The preferred build flavor of JavaScriptCore (JSC) * * For example, to use the international variant, you can use: * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` * * The international variant includes ICU i18n library and necessary data * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that - * give correct results when using with locales other than en-US. Note that + * give correct results when using with locales other than en-US. Note that * this variant is about 6MiB larger per architecture than default. */ def jscFlavor = 'org.webkit:android-jsc:+' /** - * Whether to enable the Hermes VM. - * - * This should be set on project.ext.react and that value will be read here. If it is not set - * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode - * and the benefits of using Hermes will therefore be sharply reduced. - */ -def enableHermes = project.ext.react.get("enableHermes", false); - -/** - * Architectures to build native code for. + * Private function to get the list of Native Architectures you want to build. + * This reads the value from reactNativeArchitectures in your gradle.properties + * file and works together with the --active-arch-only flag of react-native run-android. */ def reactNativeArchitectures() { def value = project.getProperties().get("reactNativeArchitectures") @@ -187,8 +148,6 @@ android { } dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - // The version of react-native is set by the React Native Gradle Plugin implementation("com.facebook.react:react-native") @@ -200,7 +159,7 @@ dependencies { } debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") - if (enableHermes) { + if (hermesEnabled.toBoolean()) { implementation("com.facebook.react:hermes-engine") } else { implementation jscFlavor diff --git a/template/android/build.gradle b/template/android/build.gradle index c6c8e7351ba0eb..c9a672214815b5 100644 --- a/template/android/build.gradle +++ b/template/android/build.gradle @@ -17,8 +17,6 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:7.3.1") classpath("com.facebook.react:react-native-gradle-plugin") - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files } } diff --git a/template/android/gradle.properties b/template/android/gradle.properties index fa4feae5f19024..e4af465e8a1857 100644 --- a/template/android/gradle.properties +++ b/template/android/gradle.properties @@ -38,3 +38,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # to write custom TurboModules/Fabric components OR use libraries that # are providing them. newArchEnabled=false + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true