From 463d4c783d21b985d666b571a7082bf429d5d822 Mon Sep 17 00:00:00 2001 From: Blake Friedman Date: Thu, 13 Jun 2024 00:31:06 -0700 Subject: [PATCH 1/2] Fix cli assemble, build & install (#44902) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44902 Add support for building (assembling) a React Native Android project. Changelog: [General][Added] core-cli-utils Android support Differential Revision: D58287783 --- .../core-cli-utils/src/private/android.js | 155 +++++++++--------- 1 file changed, 74 insertions(+), 81 deletions(-) diff --git a/packages/core-cli-utils/src/private/android.js b/packages/core-cli-utils/src/private/android.js index 9117f9130f4143..3f45f9cebb2b89 100644 --- a/packages/core-cli-utils/src/private/android.js +++ b/packages/core-cli-utils/src/private/android.js @@ -12,102 +12,92 @@ import type {Task} from './types'; import type {ExecaPromise} from 'execa'; -import {isWindows, task, toPascalCase} from './utils'; +import {isWindows, task} from './utils'; import execa from 'execa'; -type AndroidBuildMode = 'debug' | 'release'; +type AndroidBuildMode = 'Debug' | 'Release'; -type AndroidBuild = { - sourceDir: string, - appName: string, +type Path = string; +type Args = $ReadOnlyArray; + +type Config = { + cwd: Path, + hermes?: boolean, mode: AndroidBuildMode, - gradleArgs?: Array, + name: string, + newArchitecture?: boolean, + sdk?: Path, }; -function gradle(cwd: string, ...args: string[]): ExecaPromise { +function gradle( + taskName: string, + args: Args, + options: {cwd: string, env?: {[k: string]: string | void}}, +): ExecaPromise { const gradlew = isWindows ? 'gradlew.bat' : './gradlew'; - return execa(gradlew, args, { - cwd, - stdio: 'inherit', + return execa(gradlew, [taskName, ...args], { + cwd: options.cwd, + env: options.env, }); } -// -// Gradle Task wrappers -// - -/** - * Assembles an Android app using Gradle - */ -export const assemble = ( - cwd: string, - appName: string, - mode: AndroidBuildMode, - ...args: $ReadOnlyArray -): ExecaPromise => - gradle(cwd, `${appName}:assemble${toPascalCase(mode)}`, ...args); - -/** - * Assembles and tests an Android app using Gradle - */ -export const build = ( - cwd: string, - appName: string, - mode: AndroidBuildMode, - ...args: $ReadOnlyArray -): ExecaPromise => - gradle(cwd, `${appName}:build${toPascalCase(mode)}`, ...args); - -/** - * Installs an Android app using Gradle - */ -export const install = ( - cwd: string, - appName: string, - mode: AndroidBuildMode, - ...args: $ReadOnlyArray -): ExecaPromise => - gradle(cwd, `${appName}:install${toPascalCase(mode)}`, ...args); +function androidSdkPath(sdk?: string): string { + return sdk ?? process.env.ANDROID_HOME ?? process.env.ANDROID_SDK ?? ''; +} -/** - * Runs a custom Gradle task if your frameworks needs aren't handled by assemble, build or install. - */ -export const customTask = ( - cwd: string, - customTaskName: string, - ...args: $ReadOnlyArray -): ExecaPromise => gradle(cwd, customTaskName, ...args); +function boolToStr(value: boolean): string { + return value ? 'true' : 'false'; +} const FIRST = 1; // // Android Tasks // -type AndroidTasks = { - assemble: ( - options: AndroidBuild, - ...args: $ReadOnlyArray - ) => {run: Task}, - build: ( - options: AndroidBuild, - ...args: $ReadOnlyArray - ) => {run: Task}, - install: ( - options: AndroidBuild, - ...args: $ReadOnlyArray - ) => {run: Task}, -}; - -export const tasks: AndroidTasks = { - assemble: (options: AndroidBuild, ...gradleArgs: $ReadOnlyArray) => ({ - run: task(FIRST, 'Assemble Android App', () => - assemble(options.sourceDir, options.appName, options.mode, ...gradleArgs), - ), +export const tasks = ( + config: Config, +): ({ + assemble: (...gradleArgs: Args) => { + run: Task, + }, + build: (...gradleArgs: Args) => { + run: Task, + }, + install: (...gradleArgs: Args) => { + run: Task, + }, +}) => ({ + assemble: (...gradleArgs: Args) => ({ + run: task(FIRST, 'Assemble Android App', () => { + const args = []; + if (config.hermes != null) { + args.push(`-PhermesEnabled=${boolToStr(config.hermes)}`); + } + if (config.newArchitecture != null) { + args.push(`-PnewArchEnabled=${boolToStr(config.newArchitecture)}`); + } + args.push(...gradleArgs); + return gradle(`${config.name}:assemble${config.mode}`, gradleArgs, { + cwd: config.cwd, + env: {ANDROID_HOME: androidSdkPath(config.sdk)}, + }); + }), }), - build: (options: AndroidBuild, ...gradleArgs: $ReadOnlyArray) => ({ - run: task(FIRST, 'Assembles and tests Android App', () => - build(options.sourceDir, options.appName, options.mode, ...gradleArgs), - ), + build: (...gradleArgs: Args) => ({ + run: task(FIRST, 'Assembles and tests Android App', () => { + const args = []; + if (config.hermes != null) { + args.push(`-PhermesEnabled=${boolToStr(config.hermes)}`); + } + if (config.newArchitecture != null) { + args.push(`-PnewArchEnabled=${boolToStr(config.newArchitecture)}`); + } + args.push(...gradleArgs); + return gradle(`${config.name}:bundle${config.mode}`, args, { + cwd: config.cwd, + env: {ANDROID_HOME: androidSdkPath(config.sdk)}, + }); + }), }), /** * Useful extra gradle arguments: @@ -115,9 +105,12 @@ export const tasks: AndroidTasks = { * -PreactNativeDevServerPort=8081 sets the port for the installed app to point towards a Metro * server on (for example) 8081. */ - install: (options: AndroidBuild, ...gradleArgs: $ReadOnlyArray) => ({ + install: (...gradleArgs: Args) => ({ run: task(FIRST, 'Installs the assembled Android App', () => - install(options.sourceDir, options.appName, options.mode, ...gradleArgs), + gradle(`${config.name}:install${config.mode}`, gradleArgs, { + cwd: config.cwd, + env: {ANDROID_HOME: androidSdkPath(config.sdk)}, + }), ), }), @@ -125,4 +118,4 @@ export const tasks: AndroidTasks = { // a framework concern. For an example of how one could do this, please look at the community // CLI's code: // https://github.com/react-native-community/cli/blob/54d48a4e08a1aef334ae6168788e0157a666b4f5/packages/cli-platform-android/src/commands/runAndroid/index.ts#L272C1-L290C2 -}; +}); From 02a33e6eed7141587acaeca7e79610532629f15d Mon Sep 17 00:00:00 2001 From: Blake Friedman Date: Thu, 13 Jun 2024 00:43:18 -0700 Subject: [PATCH 2/2] point react gradle config to monorepo (#44901) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44901 Point Gradle to the monorepo instead of a node_modules, as well as remove some commented out entries we're not interested in. Changelog: [Internal] Reviewed By: cortinico Differential Revision: D58287786 --- packages/helloworld/android/app/build.gradle | 24 +++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/helloworld/android/app/build.gradle b/packages/helloworld/android/app/build.gradle index 7647c0d50582a7..8dc3dfad1a5fd4 100644 --- a/packages/helloworld/android/app/build.gradle +++ b/packages/helloworld/android/app/build.gradle @@ -9,6 +9,9 @@ apply plugin: "com.android.application" apply plugin: "org.jetbrains.kotlin.android" apply plugin: "com.facebook.react" +// Build a simple config (instead of depending on npx @react-native-communtiy/cli config). +def generatedConfig = file("../../.react-native.config").getText().replaceAll("HELLOWORLD_PATH", project.file("../../").absolutePath) + /** * 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. @@ -16,14 +19,14 @@ apply plugin: "com.facebook.react" react { /* Folders */ // The root of your project, i.e. where "package.json" lives. Default is '..' - // root = file("../") + root = file("../") // The folder where the react-native NPM package is. Default is ../node_modules/react-native - // reactNativeDir = file("../node_modules/react-native") + reactNativeDir = file("../../../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") - + codegenDir = file("../../../react-native-codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js, + // but now points to our simplified bundle wrapper. + cliFile = file("../../scripts/bundle.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'. @@ -34,8 +37,9 @@ react { // 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 command to run when bundling. By default is 'bundle', but since we're calling out simplified bundle + // wrapper we need this to be empty. + bundleCommand = "" // // The path to the CLI configuration file. Default is empty. // bundleConfig = file(../rn-cli.config.js) @@ -49,6 +53,10 @@ react { // 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 = [] + extraPackagerArgs = [ + "--load-config", + generatedConfig + ] /* Hermes Commands */ // The hermes compiler command to run. By default it is 'hermesc'