@react-native/gradle-plugin 0.72.2 → 0.72.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build.gradle.kts CHANGED
@@ -33,7 +33,7 @@ group = "com.facebook.react"
33
33
 
34
34
  dependencies {
35
35
  implementation(gradleApi())
36
- implementation("com.android.tools.build:gradle:7.4.0-beta05")
36
+ implementation("com.android.tools.build:gradle:7.4.1")
37
37
  implementation("com.google.code.gson:gson:2.8.9")
38
38
  implementation("com.google.guava:guava:31.0.1-jre")
39
39
  implementation("com.squareup:javapoet:1.13.0")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native/gradle-plugin",
3
- "version": "0.72.2",
3
+ "version": "0.72.4",
4
4
  "description": "⚛️ Gradle Plugin for React Native",
5
5
  "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-gradle-plugin",
6
6
  "repository": {
@@ -89,7 +89,7 @@ abstract class ReactExtension @Inject constructor(project: Project) {
89
89
  * will:
90
90
  * - Not be bundled (the bundle file will not be created and won't be copied over).
91
91
  * - Have the Hermes Debug flags set. That's useful if you have another variant (say `canary`)
92
- * where you want dev mode to be enabled. Default: ['debug']
92
+ * where you want dev mode to be enabled. Default: ['debug']
93
93
  */
94
94
  val debuggableVariants: ListProperty<String> =
95
95
  objects.listProperty(String::class.java).convention(listOf("debug"))
@@ -129,9 +129,9 @@ abstract class ReactExtension @Inject constructor(project: Project) {
129
129
  /**
130
130
  * The root directory for all JS files for the app.
131
131
  *
132
- * Default: [root] (i.e. ${rootProject.dir}/../)
132
+ * Default: the parent folder of the `/android` folder.
133
133
  */
134
- val jsRootDir: DirectoryProperty = objects.directoryProperty().convention(root.get())
134
+ val jsRootDir: DirectoryProperty = objects.directoryProperty()
135
135
 
136
136
  /**
137
137
  * The library name that will be used for the codegen artifacts.
@@ -9,6 +9,7 @@ package com.facebook.react
9
9
 
10
10
  import com.android.build.api.variant.AndroidComponentsExtension
11
11
  import com.android.build.gradle.internal.tasks.factory.dependsOn
12
+ import com.facebook.react.internal.PrivateReactExtension
12
13
  import com.facebook.react.tasks.BuildCodegenCLITask
13
14
  import com.facebook.react.tasks.GenerateCodegenArtifactsTask
14
15
  import com.facebook.react.tasks.GenerateCodegenSchemaTask
@@ -34,8 +35,22 @@ class ReactPlugin : Plugin<Project> {
34
35
  checkJvmVersion(project)
35
36
  val extension = project.extensions.create("react", ReactExtension::class.java, project)
36
37
 
38
+ // We register a private extension on the rootProject so that project wide configs
39
+ // like codegen config can be propagated from app project to libraries.
40
+ val rootExtension =
41
+ project.rootProject.extensions.findByType(PrivateReactExtension::class.java)
42
+ ?: project.rootProject.extensions.create(
43
+ "privateReact", PrivateReactExtension::class.java, project)
44
+
37
45
  // App Only Configuration
38
46
  project.pluginManager.withPlugin("com.android.application") {
47
+ // We wire the root extension with the values coming from the app (either user populated or
48
+ // defaults).
49
+ rootExtension.root.set(extension.root)
50
+ rootExtension.reactNativeDir.set(extension.reactNativeDir)
51
+ rootExtension.codegenDir.set(extension.codegenDir)
52
+ rootExtension.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)
53
+
39
54
  project.afterEvaluate {
40
55
  val reactNativeDir = extension.reactNativeDir.get().asFile
41
56
  val propertiesFile = File(reactNativeDir, "ReactAndroid/gradle.properties")
@@ -54,12 +69,12 @@ class ReactPlugin : Plugin<Project> {
54
69
  project.configureReactTasks(variant = variant, config = extension)
55
70
  }
56
71
  }
57
- configureCodegen(project, extension, isLibrary = false)
72
+ configureCodegen(project, extension, rootExtension, isLibrary = false)
58
73
  }
59
74
 
60
75
  // Library Only Configuration
61
76
  project.pluginManager.withPlugin("com.android.library") {
62
- configureCodegen(project, extension, isLibrary = true)
77
+ configureCodegen(project, extension, rootExtension, isLibrary = true)
63
78
  }
64
79
  }
65
80
 
@@ -82,25 +97,36 @@ class ReactPlugin : Plugin<Project> {
82
97
  }
83
98
  }
84
99
 
85
- /**
86
- * A plugin to enable react-native-codegen in Gradle environment. See the Gradle API docs for more
87
- * information: https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html
88
- */
100
+ /** This function sets up `react-native-codegen` in our Gradle plugin. */
89
101
  @Suppress("UnstableApiUsage")
90
- private fun configureCodegen(project: Project, extension: ReactExtension, isLibrary: Boolean) {
102
+ private fun configureCodegen(
103
+ project: Project,
104
+ localExtension: ReactExtension,
105
+ rootExtension: PrivateReactExtension,
106
+ isLibrary: Boolean
107
+ ) {
91
108
  // First, we set up the output dir for the codegen.
92
109
  val generatedSrcDir = File(project.buildDir, "generated/source/codegen")
93
110
 
111
+ // We specify the default value (convention) for jsRootDir.
112
+ // It's the root folder for apps (so ../../ from the Gradle project)
113
+ // and the package folder for library (so ../ from the Gradle project)
114
+ if (isLibrary) {
115
+ localExtension.jsRootDir.convention(project.layout.projectDirectory.dir("../"))
116
+ } else {
117
+ localExtension.jsRootDir.convention(localExtension.root)
118
+ }
119
+
94
120
  val buildCodegenTask =
95
121
  project.tasks.register("buildCodegenCLI", BuildCodegenCLITask::class.java) {
96
- it.codegenDir.set(extension.codegenDir)
122
+ it.codegenDir.set(rootExtension.codegenDir)
97
123
  val bashWindowsHome = project.findProperty("REACT_WINDOWS_BASH") as String?
98
124
  it.bashWindowsHome.set(bashWindowsHome)
99
125
 
100
126
  // Please note that appNeedsCodegen is triggering a read of the package.json at
101
127
  // configuration time as we need to feed the onlyIf condition of this task.
102
128
  // Therefore, the appNeedsCodegen needs to be invoked inside this lambda.
103
- val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(extension)
129
+ val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
104
130
  it.onlyIf { isLibrary || needsCodegenFromPackageJson }
105
131
  }
106
132
 
@@ -109,23 +135,24 @@ class ReactPlugin : Plugin<Project> {
109
135
  project.tasks.register(
110
136
  "generateCodegenSchemaFromJavaScript", GenerateCodegenSchemaTask::class.java) { it ->
111
137
  it.dependsOn(buildCodegenTask)
112
- it.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)
113
- it.codegenDir.set(extension.codegenDir)
138
+ it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
139
+ it.codegenDir.set(rootExtension.codegenDir)
114
140
  it.generatedSrcDir.set(generatedSrcDir)
115
141
 
116
142
  // We're reading the package.json at configuration time to properly feed
117
143
  // the `jsRootDir` @Input property of this task & the onlyIf. Therefore, the
118
144
  // parsePackageJson should be invoked inside this lambda.
119
- val packageJson = findPackageJsonFile(project, extension)
145
+ val packageJson = findPackageJsonFile(project, rootExtension.root)
120
146
  val parsedPackageJson = packageJson?.let { JsonUtils.fromCodegenJson(it) }
121
147
 
122
148
  val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir
123
149
  if (jsSrcsDirInPackageJson != null) {
124
150
  it.jsRootDir.set(File(packageJson.parentFile, jsSrcsDirInPackageJson))
125
151
  } else {
126
- it.jsRootDir.set(extension.jsRootDir)
152
+ it.jsRootDir.set(localExtension.jsRootDir)
127
153
  }
128
- val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(extension)
154
+ val needsCodegenFromPackageJson =
155
+ project.needsCodegenFromPackageJson(rootExtension.root)
129
156
  it.onlyIf { isLibrary || needsCodegenFromPackageJson }
130
157
  }
131
158
 
@@ -134,17 +161,18 @@ class ReactPlugin : Plugin<Project> {
134
161
  project.tasks.register(
135
162
  "generateCodegenArtifactsFromSchema", GenerateCodegenArtifactsTask::class.java) {
136
163
  it.dependsOn(generateCodegenSchemaTask)
137
- it.reactNativeDir.set(extension.reactNativeDir)
138
- it.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)
164
+ it.reactNativeDir.set(rootExtension.reactNativeDir)
165
+ it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
139
166
  it.generatedSrcDir.set(generatedSrcDir)
140
- it.packageJsonFile.set(findPackageJsonFile(project, extension))
141
- it.codegenJavaPackageName.set(extension.codegenJavaPackageName)
142
- it.libraryName.set(extension.libraryName)
167
+ it.packageJsonFile.set(findPackageJsonFile(project, rootExtension.root))
168
+ it.codegenJavaPackageName.set(localExtension.codegenJavaPackageName)
169
+ it.libraryName.set(localExtension.libraryName)
143
170
 
144
171
  // Please note that appNeedsCodegen is triggering a read of the package.json at
145
172
  // configuration time as we need to feed the onlyIf condition of this task.
146
173
  // Therefore, the appNeedsCodegen needs to be invoked inside this lambda.
147
- val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(extension)
174
+ val needsCodegenFromPackageJson =
175
+ project.needsCodegenFromPackageJson(rootExtension.root)
148
176
  it.onlyIf { isLibrary || needsCodegenFromPackageJson }
149
177
  }
150
178
 
@@ -22,14 +22,16 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio
22
22
  val targetName = variant.name.replaceFirstChar { it.uppercase() }
23
23
  val targetPath = variant.name
24
24
 
25
- // React js bundle directories
25
+ // Resources: generated/assets/react/<variant>/index.android.bundle
26
26
  val resourcesDir = File(buildDir, "generated/res/react/$targetPath")
27
- // Bundle: generated/assets/react/path/index.android.bundle
27
+ // Bundle: generated/assets/react/<variant>/index.android.bundle
28
28
  val jsBundleDir = File(buildDir, "generated/assets/react/$targetPath")
29
- // Sourcemap: generated/sourcemaps/react/path/index.android.bundle.map
29
+ // Sourcemap: generated/sourcemaps/react/<variant>/index.android.bundle.map
30
30
  val jsSourceMapsDir = File(buildDir, "generated/sourcemaps/react/$targetPath")
31
- // Intermediate packager: intermediates/sourcemaps/react/path/index.android.bundle.packager.map
32
- // Intermediate compiler: intermediates/sourcemaps/react/path/index.android.bundle.compiler.map
31
+ // Intermediate packager:
32
+ // intermediates/sourcemaps/react/<variant>/index.android.bundle.packager.map
33
+ // Intermediate compiler:
34
+ // intermediates/sourcemaps/react/<variant>/index.android.bundle.compiler.map
33
35
  val jsIntermediateSourceMapsDir = File(buildDir, "intermediates/sourcemaps/react/$targetPath")
34
36
 
35
37
  // The location of the cli.js file for React Native
@@ -49,13 +51,14 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio
49
51
  configureJsEnginePackagingOptions(config, variant, isHermesEnabledInThisVariant)
50
52
 
51
53
  if (!isDebuggableVariant) {
54
+ val entryFileEnvVariable = System.getenv("ENTRY_FILE")
52
55
  val bundleTask =
53
56
  tasks.register("createBundle${targetName}JsAndAssets", BundleHermesCTask::class.java) {
54
57
  it.root.set(config.root)
55
58
  it.nodeExecutableAndArgs.set(config.nodeExecutableAndArgs)
56
59
  it.cliFile.set(cliFile)
57
60
  it.bundleCommand.set(config.bundleCommand)
58
- it.entryFile.set(detectedEntryFile(config))
61
+ it.entryFile.set(detectedEntryFile(config, entryFileEnvVariable))
59
62
  it.extraPackagerArgs.set(config.extraPackagerArgs)
60
63
  it.bundleConfig.set(config.bundleConfig)
61
64
  it.bundleAssetName.set(config.bundleAssetName)
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ package com.facebook.react.internal
9
+
10
+ import javax.inject.Inject
11
+ import org.gradle.api.Project
12
+ import org.gradle.api.file.DirectoryProperty
13
+ import org.gradle.api.provider.ListProperty
14
+
15
+ /**
16
+ * A private extension we set on the rootProject to make easier to share values at execution time
17
+ * between app project and library project.
18
+ *
19
+ * Specifically, the [codegenDir], [reactNativeDir] and other properties should be provided by apps
20
+ * (for setups like a monorepo which are app specific) and libraries should honor those values.
21
+ *
22
+ * Users are not supposed to access directly this extension from their build.gradle file.
23
+ */
24
+ abstract class PrivateReactExtension @Inject constructor(project: Project) {
25
+
26
+ private val objects = project.objects
27
+
28
+ val root: DirectoryProperty =
29
+ objects
30
+ .directoryProperty()
31
+ .convention(
32
+ // This is the default for the project root if the users hasn't specified anything.
33
+ // If the project is called "react-native-github"
34
+ // - We're inside the Github Repo -> root is defined by RN Tester (so no default
35
+ // needed)
36
+ // - We're inside an includedBuild as we're performing a build from source
37
+ // (then we're inside `node_modules/react-native`, so default should be ../../)
38
+ // If the project is called in any other name
39
+ // - We're inside a user project, so inside the ./android folder. Default should be
40
+ // ../
41
+ // User can always override this default by setting a `root =` inside the template.
42
+ if (project.rootProject.name == "react-native-github") {
43
+ project.rootProject.layout.projectDirectory.dir("../../")
44
+ } else {
45
+ project.rootProject.layout.projectDirectory.dir("../")
46
+ })
47
+
48
+ val reactNativeDir: DirectoryProperty =
49
+ objects.directoryProperty().convention(root.dir("node_modules/react-native"))
50
+
51
+ val nodeExecutableAndArgs: ListProperty<String> =
52
+ objects.listProperty(String::class.java).convention(listOf("node"))
53
+
54
+ val codegenDir: DirectoryProperty =
55
+ objects.directoryProperty().convention(root.dir("node_modules/@react-native/codegen"))
56
+ }
@@ -7,6 +7,7 @@
7
7
 
8
8
  package com.facebook.react.tasks
9
9
 
10
+ import com.facebook.react.utils.Os.cliPath
10
11
  import com.facebook.react.utils.detectOSAwareHermesCommand
11
12
  import com.facebook.react.utils.moveTo
12
13
  import com.facebook.react.utils.windowsAwareCommandLine
@@ -135,8 +136,9 @@ abstract class BundleHermesCTask : DefaultTask() {
135
136
  internal fun getBundleCommand(bundleFile: File, sourceMapFile: File): List<Any> =
136
137
  windowsAwareCommandLine(
137
138
  buildList {
139
+ val rootFile = root.get().asFile
138
140
  addAll(nodeExecutableAndArgs.get())
139
- add(cliFile.get().asFile.absolutePath)
141
+ add(cliFile.get().asFile.cliPath(rootFile))
140
142
  add(bundleCommand.get())
141
143
  add("--platform")
142
144
  add("android")
@@ -144,16 +146,16 @@ abstract class BundleHermesCTask : DefaultTask() {
144
146
  add(devEnabled.get().toString())
145
147
  add("--reset-cache")
146
148
  add("--entry-file")
147
- add(entryFile.get().asFile.toString())
149
+ add(entryFile.get().asFile.cliPath(rootFile))
148
150
  add("--bundle-output")
149
- add(bundleFile.toString())
151
+ add(bundleFile.cliPath(rootFile))
150
152
  add("--assets-dest")
151
- add(resourcesDir.get().asFile.toString())
153
+ add(resourcesDir.get().asFile.cliPath(rootFile))
152
154
  add("--sourcemap-output")
153
- add(sourceMapFile.toString())
155
+ add(sourceMapFile.cliPath(rootFile))
154
156
  if (bundleConfig.isPresent) {
155
157
  add("--config")
156
- add(bundleConfig.get().asFile.absolutePath)
158
+ add(bundleConfig.get().asFile.cliPath(rootFile))
157
159
  }
158
160
  add("--minify")
159
161
  add(minifyEnabled.get().toString())
@@ -165,26 +167,30 @@ abstract class BundleHermesCTask : DefaultTask() {
165
167
  hermesCommand: String,
166
168
  bytecodeFile: File,
167
169
  bundleFile: File
168
- ): List<Any> =
169
- windowsAwareCommandLine(
170
- hermesCommand,
171
- "-emit-binary",
172
- "-out",
173
- bytecodeFile.absolutePath,
174
- bundleFile.absolutePath,
175
- *hermesFlags.get().toTypedArray())
170
+ ): List<Any> {
171
+ val rootFile = root.get().asFile
172
+ return windowsAwareCommandLine(
173
+ hermesCommand,
174
+ "-emit-binary",
175
+ "-out",
176
+ bytecodeFile.cliPath(rootFile),
177
+ bundleFile.cliPath(rootFile),
178
+ *hermesFlags.get().toTypedArray())
179
+ }
176
180
 
177
181
  internal fun getComposeSourceMapsCommand(
178
182
  composeScript: File,
179
183
  packagerSourceMap: File,
180
184
  compilerSourceMap: File,
181
185
  outputSourceMap: File
182
- ): List<Any> =
183
- windowsAwareCommandLine(
184
- *nodeExecutableAndArgs.get().toTypedArray(),
185
- composeScript.absolutePath,
186
- packagerSourceMap.toString(),
187
- compilerSourceMap.toString(),
188
- "-o",
189
- outputSourceMap.toString())
186
+ ): List<Any> {
187
+ val rootFile = root.get().asFile
188
+ return windowsAwareCommandLine(
189
+ *nodeExecutableAndArgs.get().toTypedArray(),
190
+ composeScript.cliPath(rootFile),
191
+ packagerSourceMap.cliPath(rootFile),
192
+ compilerSourceMap.cliPath(rootFile),
193
+ "-o",
194
+ outputSourceMap.cliPath(rootFile))
195
+ }
190
196
  }
@@ -8,6 +8,7 @@
8
8
  package com.facebook.react.tasks
9
9
 
10
10
  import com.facebook.react.utils.JsonUtils
11
+ import com.facebook.react.utils.Os.cliPath
11
12
  import com.facebook.react.utils.windowsAwareCommandLine
12
13
  import org.gradle.api.file.Directory
13
14
  import org.gradle.api.file.DirectoryProperty
@@ -63,16 +64,17 @@ abstract class GenerateCodegenArtifactsTask : Exec() {
63
64
  }
64
65
 
65
66
  internal fun setupCommandLine(libraryName: String, codegenJavaPackageName: String) {
67
+ val workingDir = project.projectDir
66
68
  commandLine(
67
69
  windowsAwareCommandLine(
68
70
  *nodeExecutableAndArgs.get().toTypedArray(),
69
- reactNativeDir.file("scripts/generate-specs-cli.js").get().asFile.absolutePath,
71
+ reactNativeDir.file("scripts/generate-specs-cli.js").get().asFile.cliPath(workingDir),
70
72
  "--platform",
71
73
  "android",
72
74
  "--schemaPath",
73
- generatedSchemaFile.get().asFile.absolutePath,
75
+ generatedSchemaFile.get().asFile.cliPath(workingDir),
74
76
  "--outputDir",
75
- generatedSrcDir.get().asFile.absolutePath,
77
+ generatedSrcDir.get().asFile.cliPath(workingDir),
76
78
  "--libraryName",
77
79
  libraryName,
78
80
  "--javaPackageName",
@@ -7,6 +7,7 @@
7
7
 
8
8
  package com.facebook.react.tasks
9
9
 
10
+ import com.facebook.react.utils.Os.cliPath
10
11
  import com.facebook.react.utils.windowsAwareCommandLine
11
12
  import org.gradle.api.file.DirectoryProperty
12
13
  import org.gradle.api.file.RegularFile
@@ -63,6 +64,7 @@ abstract class GenerateCodegenSchemaTask : Exec() {
63
64
  }
64
65
 
65
66
  internal fun setupCommandLine() {
67
+ val workingDir = project.projectDir
66
68
  commandLine(
67
69
  windowsAwareCommandLine(
68
70
  *nodeExecutableAndArgs.get().toTypedArray(),
@@ -70,11 +72,11 @@ abstract class GenerateCodegenSchemaTask : Exec() {
70
72
  .file("lib/cli/combine/combine-js-to-schema-cli.js")
71
73
  .get()
72
74
  .asFile
73
- .absolutePath,
75
+ .cliPath(workingDir),
74
76
  "--platform",
75
77
  "android",
76
- generatedSchemaFile.get().asFile.absolutePath,
77
- jsRootDir.asFile.get().absolutePath,
78
+ generatedSchemaFile.get().asFile.cliPath(workingDir),
79
+ jsRootDir.asFile.get().cliPath(workingDir),
78
80
  ))
79
81
  }
80
82
  }
@@ -11,10 +11,11 @@ import java.io.Serializable
11
11
 
12
12
  /**
13
13
  * This data class represents an entry that can be consumed by the [PreparePrefabHeadersTask].
14
+ *
14
15
  * @param libraryName The name of the library that you're preparing for Prefab
15
16
  * @param pathToPrefixCouples A list of pairs Path to Header prefix. You can use this list to supply
16
- * a list of paths that you want to be considered for prefab. Each path can specify an header prefix
17
- * that will be used by prefab to re-created the header layout.
17
+ * a list of paths that you want to be considered for prefab. Each path can specify an header
18
+ * prefix that will be used by prefab to re-created the header layout.
18
19
  */
19
20
  data class PrefabPreprocessingEntry(
20
21
  val libraryName: String,
@@ -10,6 +10,7 @@ package com.facebook.react.utils
10
10
  import com.android.build.api.variant.AndroidComponentsExtension
11
11
  import com.android.build.api.variant.Variant
12
12
  import com.facebook.react.ReactExtension
13
+ import com.facebook.react.utils.ProjectUtils.getReactNativeArchitectures
13
14
  import com.facebook.react.utils.ProjectUtils.isNewArchEnabled
14
15
  import java.io.File
15
16
  import org.gradle.api.Project
@@ -49,6 +50,13 @@ internal object NdkConfiguratorUtils {
49
50
  if ("-DANDROID_STL" !in cmakeArgs) {
50
51
  cmakeArgs.add("-DANDROID_STL=c++_shared")
51
52
  }
53
+
54
+ val architectures = project.getReactNativeArchitectures()
55
+ // abiFilters are split ABI are not compatible each other, so we set the abiFilters
56
+ // only if the user hasn't enabled the split abi feature.
57
+ if (architectures.isNotEmpty() && !ext.splits.abi.isEnable) {
58
+ ext.defaultConfig.ndk.abiFilters.addAll(architectures)
59
+ }
52
60
  }
53
61
  }
54
62
  }
@@ -7,7 +7,9 @@
7
7
 
8
8
  package com.facebook.react.utils
9
9
 
10
- object Os {
10
+ import java.io.File
11
+
12
+ internal object Os {
11
13
 
12
14
  fun isWindows(): Boolean =
13
15
  System.getProperty("os.name")?.lowercase()?.contains("windows") ?: false
@@ -28,4 +30,15 @@ object Os {
28
30
  it
29
31
  }
30
32
  }
33
+
34
+ /**
35
+ * As Gradle doesn't support well path with spaces on Windows, we need to return relative path on
36
+ * Win. On Linux & Mac we'll default to return absolute path.
37
+ */
38
+ fun File.cliPath(base: File): String =
39
+ if (isWindows()) {
40
+ this.relativeTo(base).path
41
+ } else {
42
+ this.absolutePath
43
+ }
31
44
  }
@@ -11,8 +11,10 @@ package com.facebook.react.utils
11
11
 
12
12
  import com.facebook.react.ReactExtension
13
13
  import com.facebook.react.model.ModelPackageJson
14
+ import com.facebook.react.utils.Os.cliPath
14
15
  import java.io.File
15
16
  import org.gradle.api.Project
17
+ import org.gradle.api.file.DirectoryProperty
16
18
 
17
19
  /**
18
20
  * Computes the entry file for React Native. The Algo follows this order:
@@ -23,9 +25,11 @@ import org.gradle.api.Project
23
25
  *
24
26
  * @param config The [ReactExtension] configured for this project
25
27
  */
26
- internal fun detectedEntryFile(config: ReactExtension): File =
28
+ internal fun detectedEntryFile(config: ReactExtension, envVariableOverride: String? = null): File =
27
29
  detectEntryFile(
28
- entryFile = config.entryFile.orNull?.asFile, reactRoot = config.root.get().asFile)
30
+ entryFile = config.entryFile.orNull?.asFile,
31
+ reactRoot = config.root.get().asFile,
32
+ envVariableOverride = envVariableOverride)
29
33
 
30
34
  /**
31
35
  * Computes the CLI file for React Native. The Algo follows this order:
@@ -43,18 +47,22 @@ internal fun detectedCliFile(config: ReactExtension): File =
43
47
  * Computes the `hermesc` command location. The Algo follows this order:
44
48
  * 1. The path provided by the `hermesCommand` config in the `react` Gradle extension
45
49
  * 2. The file located in `node_modules/react-native/sdks/hermes/build/bin/hermesc`. This will be
46
- * used if the user is building Hermes from source.
50
+ * used if the user is building Hermes from source.
47
51
  * 3. The file located in `node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc` where `%OS-BIN%`
48
- * is substituted with the correct OS arch. This will be used if the user is using a precompiled
49
- * hermes-engine package.
52
+ * is substituted with the correct OS arch. This will be used if the user is using a precompiled
53
+ * hermes-engine package.
50
54
  * 4. Fails otherwise
51
55
  */
52
56
  internal fun detectedHermesCommand(config: ReactExtension): String =
53
57
  detectOSAwareHermesCommand(config.root.get().asFile, config.hermesCommand.get())
54
58
 
55
- private fun detectEntryFile(entryFile: File?, reactRoot: File): File =
59
+ private fun detectEntryFile(
60
+ entryFile: File?,
61
+ reactRoot: File,
62
+ envVariableOverride: String? = null
63
+ ): File =
56
64
  when {
57
- System.getenv("ENTRY_FILE") != null -> File(System.getenv("ENTRY_FILE"))
65
+ envVariableOverride != null -> File(reactRoot, envVariableOverride)
58
66
  entryFile != null -> entryFile
59
67
  File(reactRoot, "index.android.js").exists() -> File(reactRoot, "index.android.js")
60
68
  else -> File(reactRoot, "index.js")
@@ -106,10 +114,10 @@ private fun detectCliFile(reactNativeRoot: File, preconfiguredCliFile: File?): F
106
114
  * Computes the `hermesc` command location. The Algo follows this order:
107
115
  * 1. The path provided by the `hermesCommand` config in the `react` Gradle extension
108
116
  * 2. The file located in `node_modules/react-native/sdks/hermes/build/bin/hermesc`. This will be
109
- * used if the user is building Hermes from source.
117
+ * used if the user is building Hermes from source.
110
118
  * 3. The file located in `node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc` where `%OS-BIN%`
111
- * is substituted with the correct OS arch. This will be used if the user is using a precompiled
112
- * hermes-engine package.
119
+ * is substituted with the correct OS arch. This will be used if the user is using a precompiled
120
+ * hermes-engine package.
113
121
  * 4. Fails otherwise
114
122
  */
115
123
  internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String): String {
@@ -130,7 +138,7 @@ internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String
130
138
  val builtHermesc =
131
139
  getBuiltHermescFile(projectRoot, System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR"))
132
140
  if (builtHermesc.exists()) {
133
- return builtHermesc.absolutePath
141
+ return builtHermesc.cliPath(projectRoot)
134
142
  }
135
143
 
136
144
  // 3. If the react-native contains a pre-built hermesc, use it.
@@ -142,7 +150,7 @@ internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String
142
150
 
143
151
  val prebuiltHermes = File(projectRoot, prebuiltHermesPath)
144
152
  if (prebuiltHermes.exists()) {
145
- return prebuiltHermes.absolutePath
153
+ return prebuiltHermes.cliPath(projectRoot)
146
154
  }
147
155
 
148
156
  error(
@@ -188,13 +196,13 @@ internal fun projectPathToLibraryName(projectPath: String): String =
188
196
  * Gradle module (generally the case for library projects) or we fallback to looking into the `root`
189
197
  * folder of a React Native project (generally the case for app projects).
190
198
  */
191
- internal fun findPackageJsonFile(project: Project, extension: ReactExtension): File? {
199
+ internal fun findPackageJsonFile(project: Project, rootProperty: DirectoryProperty): File? {
192
200
  val inParent = project.file("../package.json")
193
201
  if (inParent.exists()) {
194
202
  return inParent
195
203
  }
196
204
 
197
- val fromExtension = extension.root.file("package.json").orNull?.asFile
205
+ val fromExtension = rootProperty.file("package.json").orNull?.asFile
198
206
  if (fromExtension?.exists() == true) {
199
207
  return fromExtension
200
208
  }
@@ -206,12 +214,15 @@ internal fun findPackageJsonFile(project: Project, extension: ReactExtension): F
206
214
  * Function to look for the `package.json` and parse it. It returns a [ModelPackageJson] if found or
207
215
  * null others.
208
216
  *
209
- * Please note that this function access the [ReactExtension] field properties and calls .get() on
210
- * them, so calling this during apply() of the ReactPlugin is not recommended. It should be invoked
211
- * inside lazy lambdas or at execution time.
217
+ * Please note that this function access the [DirectoryProperty] parameter and calls .get() on them,
218
+ * so calling this during apply() of the ReactPlugin is not recommended. It should be invoked inside
219
+ * lazy lambdas or at execution time.
212
220
  */
213
- internal fun readPackageJsonFile(project: Project, extension: ReactExtension): ModelPackageJson? {
214
- val packageJson = findPackageJsonFile(project, extension)
221
+ internal fun readPackageJsonFile(
222
+ project: Project,
223
+ rootProperty: DirectoryProperty
224
+ ): ModelPackageJson? {
225
+ val packageJson = findPackageJsonFile(project, rootProperty)
215
226
  return packageJson?.let { JsonUtils.fromCodegenJson(it) }
216
227
  }
217
228
 
@@ -7,9 +7,9 @@
7
7
 
8
8
  package com.facebook.react.utils
9
9
 
10
- import com.facebook.react.ReactExtension
11
10
  import com.facebook.react.model.ModelPackageJson
12
11
  import org.gradle.api.Project
12
+ import org.gradle.api.file.DirectoryProperty
13
13
 
14
14
  internal object ProjectUtils {
15
15
  internal val Project.isNewArchEnabled: Boolean
@@ -35,12 +35,21 @@ internal object ProjectUtils {
35
35
  HERMES_FALLBACK
36
36
  }
37
37
 
38
- internal fun Project.needsCodegenFromPackageJson(extension: ReactExtension): Boolean {
39
- val parsedPackageJson = readPackageJsonFile(this, extension)
38
+ internal fun Project.needsCodegenFromPackageJson(rootProperty: DirectoryProperty): Boolean {
39
+ val parsedPackageJson = readPackageJsonFile(this, rootProperty)
40
40
  return needsCodegenFromPackageJson(parsedPackageJson)
41
41
  }
42
42
 
43
43
  internal fun Project.needsCodegenFromPackageJson(model: ModelPackageJson?): Boolean {
44
44
  return model?.codegenConfig != null
45
45
  }
46
+
47
+ internal fun Project.getReactNativeArchitectures(): List<String> {
48
+ val architectures = mutableListOf<String>()
49
+ if (project.hasProperty("reactNativeArchitectures")) {
50
+ val architecturesString = project.property("reactNativeArchitectures").toString()
51
+ architectures.addAll(architecturesString.split(",").filter { it.isNotBlank() })
52
+ }
53
+ return architectures
54
+ }
46
55
  }