@ohos-ports/react-native-gradle-plugin 0.71.19-beta.0

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.
Files changed (37) hide show
  1. package/README.md +16 -0
  2. package/build/libs/react-native-gradle-plugin.jar +0 -0
  3. package/build.gradle.kts +59 -0
  4. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  5. package/gradle/wrapper/gradle-wrapper.properties +5 -0
  6. package/gradlew +234 -0
  7. package/gradlew.bat +89 -0
  8. package/index.js +73 -0
  9. package/package.json +30 -0
  10. package/settings.gradle.kts +16 -0
  11. package/src/main/kotlin/com/facebook/react/ReactExtension.kt +151 -0
  12. package/src/main/kotlin/com/facebook/react/ReactPlugin.kt +212 -0
  13. package/src/main/kotlin/com/facebook/react/TaskConfiguration.kt +81 -0
  14. package/src/main/kotlin/com/facebook/react/internal/PrivateReactExtension.kt +56 -0
  15. package/src/main/kotlin/com/facebook/react/model/ModelCodegenConfig.kt +15 -0
  16. package/src/main/kotlin/com/facebook/react/model/ModelCodegenConfigAndroid.kt +10 -0
  17. package/src/main/kotlin/com/facebook/react/model/ModelPackageJson.kt +10 -0
  18. package/src/main/kotlin/com/facebook/react/tasks/BuildCodegenCLITask.kt +58 -0
  19. package/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt +200 -0
  20. package/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTask.kt +83 -0
  21. package/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt +82 -0
  22. package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareBoostTask.kt +46 -0
  23. package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareGlogTask.kt +79 -0
  24. package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareJSCTask.kt +50 -0
  25. package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareLibeventTask.kt +51 -0
  26. package/src/main/kotlin/com/facebook/react/tasks/internal/PreparePrefabHeadersTask.kt +62 -0
  27. package/src/main/kotlin/com/facebook/react/tasks/internal/utils/PrefabPreprocessingEntry.kt +27 -0
  28. package/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt +54 -0
  29. package/src/main/kotlin/com/facebook/react/utils/BackwardCompatUtils.kt +48 -0
  30. package/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt +109 -0
  31. package/src/main/kotlin/com/facebook/react/utils/FileUtils.kt +20 -0
  32. package/src/main/kotlin/com/facebook/react/utils/JsonUtils.kt +21 -0
  33. package/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt +147 -0
  34. package/src/main/kotlin/com/facebook/react/utils/Os.kt +44 -0
  35. package/src/main/kotlin/com/facebook/react/utils/PathUtils.kt +231 -0
  36. package/src/main/kotlin/com/facebook/react/utils/ProjectUtils.kt +55 -0
  37. package/src/main/kotlin/com/facebook/react/utils/TaskUtils.kt +28 -0
@@ -0,0 +1,109 @@
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.utils
9
+
10
+ import java.io.File
11
+ import java.net.URI
12
+ import java.util.*
13
+ import org.gradle.api.Project
14
+ import org.gradle.api.artifacts.repositories.MavenArtifactRepository
15
+
16
+ internal const val DEFAULT_GROUP_STRING = "com.facebook.react"
17
+
18
+ internal object DependencyUtils {
19
+
20
+ /**
21
+ * This method takes care of configuring the repositories{} block for both the app and all the 3rd
22
+ * party libraries which are auto-linked.
23
+ */
24
+ fun configureRepositories(project: Project, reactNativeDir: File) {
25
+ project.rootProject.allprojects { eachProject ->
26
+ with(eachProject) {
27
+ if (hasProperty("REACT_NATIVE_MAVEN_LOCAL_REPO")) {
28
+ val mavenLocalRepoPath = property("REACT_NATIVE_MAVEN_LOCAL_REPO") as String
29
+ mavenRepoFromURI(File(mavenLocalRepoPath).toURI())
30
+ }
31
+ // We add the snapshot for users on nightlies.
32
+ mavenRepoFromUrl("https://oss.sonatype.org/content/repositories/snapshots/")
33
+ repositories.mavenCentral()
34
+ // Android JSC is installed from npm
35
+ mavenRepoFromURI(File(reactNativeDir, "../jsc-android/dist").toURI())
36
+ repositories.google()
37
+ mavenRepoFromUrl("https://www.jitpack.io")
38
+ }
39
+ }
40
+ }
41
+
42
+ /**
43
+ * This method takes care of configuring the resolution strategy for both the app and all the 3rd
44
+ * party libraries which are auto-linked. Specifically it takes care of:
45
+ * - Forcing the react-android/hermes-android version to the one specified in the package.json
46
+ * - Substituting `react-native` with `react-android` and `hermes-engine` with `hermes-android`.
47
+ */
48
+ fun configureDependencies(
49
+ project: Project,
50
+ versionString: String,
51
+ groupString: String = DEFAULT_GROUP_STRING
52
+ ) {
53
+ if (versionString.isBlank()) return
54
+ project.rootProject.allprojects { eachProject ->
55
+ eachProject.configurations.all { configuration ->
56
+ // Here we set a dependencySubstitution for both react-native and hermes-engine as those
57
+ // coordinates are voided due to https://github.com/facebook/react-native/issues/35210
58
+ // This allows users to import libraries that are still using
59
+ // implementation("com.facebook.react:react-native:+") and resolve the right dependency.
60
+ configuration.resolutionStrategy.dependencySubstitution {
61
+ it.substitute(it.module("com.facebook.react:react-native"))
62
+ .using(it.module("${groupString}:react-android:${versionString}"))
63
+ .because(
64
+ "The react-native artifact was deprecated in favor of react-android due to https://github.com/facebook/react-native/issues/35210.")
65
+ it.substitute(it.module("com.facebook.react:hermes-engine"))
66
+ .using(it.module("${groupString}:hermes-android:${versionString}"))
67
+ .because(
68
+ "The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210.")
69
+ if (groupString != DEFAULT_GROUP_STRING) {
70
+ it.substitute(it.module("com.facebook.react:react-android"))
71
+ .using(it.module("${groupString}:react-android:${versionString}"))
72
+ .because(
73
+ "The react-android dependency was modified to use the correct Maven group.")
74
+ it.substitute(it.module("com.facebook.react:hermes-android"))
75
+ .using(it.module("${groupString}:hermes-android:${versionString}"))
76
+ .because(
77
+ "The hermes-android dependency was modified to use the correct Maven group.")
78
+ }
79
+ }
80
+ configuration.resolutionStrategy.force(
81
+ "${groupString}:react-android:${versionString}",
82
+ "${groupString}:hermes-android:${versionString}",
83
+ )
84
+ }
85
+ }
86
+ }
87
+
88
+ fun readVersionAndGroupStrings(propertiesFile: File): Pair<String, String> {
89
+ val reactAndroidProperties = Properties()
90
+ propertiesFile.inputStream().use { reactAndroidProperties.load(it) }
91
+ val versionStringFromFile = reactAndroidProperties["VERSION_NAME"] as? String ?: ""
92
+ // If on a nightly, we need to fetch the -SNAPSHOT artifact from Sonatype.
93
+ val versionString =
94
+ if (versionStringFromFile.startsWith("0.0.0")) {
95
+ "$versionStringFromFile-SNAPSHOT"
96
+ } else {
97
+ versionStringFromFile
98
+ }
99
+ // Returns Maven group for repos using different group for Maven artifacts
100
+ val groupString = reactAndroidProperties["GROUP"] as? String ?: DEFAULT_GROUP_STRING
101
+ return Pair(versionString, groupString)
102
+ }
103
+
104
+ fun Project.mavenRepoFromUrl(url: String): MavenArtifactRepository =
105
+ project.repositories.maven { it.url = URI.create(url) }
106
+
107
+ fun Project.mavenRepoFromURI(uri: URI): MavenArtifactRepository =
108
+ project.repositories.maven { it.url = uri }
109
+ }
@@ -0,0 +1,20 @@
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.utils
9
+
10
+ import java.io.File
11
+
12
+ internal fun File.moveTo(destination: File) {
13
+ copyTo(destination, overwrite = true)
14
+ delete()
15
+ }
16
+
17
+ internal fun File.recreateDir() {
18
+ deleteRecursively()
19
+ mkdirs()
20
+ }
@@ -0,0 +1,21 @@
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.utils
9
+
10
+ import com.facebook.react.model.ModelPackageJson
11
+ import com.google.gson.Gson
12
+ import java.io.File
13
+
14
+ object JsonUtils {
15
+ private val gsonConverter = Gson()
16
+
17
+ fun fromCodegenJson(input: File): ModelPackageJson? =
18
+ input.bufferedReader().use {
19
+ runCatching { gsonConverter.fromJson(it, ModelPackageJson::class.java) }.getOrNull()
20
+ }
21
+ }
@@ -0,0 +1,147 @@
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.utils
9
+
10
+ import com.android.build.api.variant.AndroidComponentsExtension
11
+ import com.android.build.api.variant.Variant
12
+ import com.facebook.react.ReactExtension
13
+ import com.facebook.react.utils.ProjectUtils.getReactNativeArchitectures
14
+ import com.facebook.react.utils.ProjectUtils.isNewArchEnabled
15
+ import java.io.File
16
+ import org.gradle.api.Project
17
+
18
+ internal object NdkConfiguratorUtils {
19
+ @Suppress("UnstableApiUsage")
20
+ fun configureReactNativeNdk(project: Project, extension: ReactExtension) {
21
+ project.pluginManager.withPlugin("com.android.application") {
22
+ project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext ->
23
+ if (!project.isNewArchEnabled) {
24
+ // For Old Arch, we don't need to setup the NDK
25
+ return@finalizeDsl
26
+ }
27
+ // We enable prefab so users can consume .so/headers from ReactAndroid and hermes-engine
28
+ // .aar
29
+ ext.buildFeatures.prefab = true
30
+
31
+ // If the user has not provided a CmakeLists.txt path, let's provide
32
+ // the default one from the framework
33
+ if (ext.externalNativeBuild.cmake.path == null) {
34
+ ext.externalNativeBuild.cmake.path =
35
+ File(
36
+ extension.reactNativeDir.get().asFile,
37
+ "ReactAndroid/cmake-utils/default-app-setup/CMakeLists.txt")
38
+ }
39
+
40
+ // Parameters should be provided in an additive manner (do not override what
41
+ // the user provided, but allow for sensible defaults).
42
+ val cmakeArgs = ext.defaultConfig.externalNativeBuild.cmake.arguments
43
+ if ("-DPROJECT_BUILD_DIR" !in cmakeArgs) {
44
+ cmakeArgs.add("-DPROJECT_BUILD_DIR=${project.buildDir}")
45
+ }
46
+ if ("-DREACT_ANDROID_DIR" !in cmakeArgs) {
47
+ cmakeArgs.add(
48
+ "-DREACT_ANDROID_DIR=${extension.reactNativeDir.file("ReactAndroid").get().asFile}")
49
+ }
50
+ if ("-DANDROID_STL" !in cmakeArgs) {
51
+ cmakeArgs.add("-DANDROID_STL=c++_shared")
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
+ }
60
+ }
61
+ }
62
+ }
63
+
64
+ /**
65
+ * This method is used to configure the .so Packaging Options for the given variant. It will make
66
+ * sure we specify the correct .pickFirsts for all the .so files we are producing or that we're
67
+ * aware of as some of our dependencies are pulling them in.
68
+ */
69
+ fun configureNewArchPackagingOptions(
70
+ project: Project,
71
+ variant: Variant,
72
+ ) {
73
+ if (!project.isNewArchEnabled) {
74
+ // For Old Arch, we set a pickFirst only on libraries that we know are
75
+ // clashing with our direct dependencies (FBJNI, Flipper and Hermes).
76
+ variant.packaging.jniLibs.pickFirsts.addAll(
77
+ listOf(
78
+ "**/libfbjni.so",
79
+ "**/libc++_shared.so",
80
+ ))
81
+ } else {
82
+ // We set some packagingOptions { pickFirst ... } for our users for libraries we own.
83
+ variant.packaging.jniLibs.pickFirsts.addAll(
84
+ listOf(
85
+ // This is the .so provided by FBJNI via prefab
86
+ "**/libfbjni.so",
87
+ // Those are prefab libraries we distribute via ReactAndroid
88
+ // Due to a bug in AGP, they fire a warning on console as both the JNI
89
+ // and the prefab .so files gets considered. See more on:
90
+ "**/libfabricjni.so",
91
+ "**/libfolly_runtime.so",
92
+ "**/libglog.so",
93
+ "**/libjsi.so",
94
+ "**/libreact_codegen_rncore.so",
95
+ "**/libreact_debug.so",
96
+ "**/libreact_nativemodule_core.so",
97
+ "**/libreact_newarchdefaults.so",
98
+ "**/libreact_render_componentregistry.so",
99
+ "**/libreact_render_core.so",
100
+ "**/libreact_render_debug.so",
101
+ "**/libreact_render_graphics.so",
102
+ "**/libreact_render_imagemanager.so",
103
+ "**/libreact_render_mapbuffer.so",
104
+ "**/librrc_image.so",
105
+ "**/librrc_view.so",
106
+ "**/libruntimeexecutor.so",
107
+ "**/libturbomodulejsijni.so",
108
+ "**/libyoga.so",
109
+ // AGP will give priority of libc++_shared coming from App modules.
110
+ "**/libc++_shared.so",
111
+ ))
112
+ }
113
+ }
114
+
115
+ /**
116
+ * This method is used to configure the .so Cleanup for the given variant. It takes care of
117
+ * cleaning up the .so files that are not needed for Hermes or JSC, given a specific variant.
118
+ */
119
+ fun configureJsEnginePackagingOptions(
120
+ config: ReactExtension,
121
+ variant: Variant,
122
+ hermesEnabled: Boolean,
123
+ ) {
124
+ if (config.enableSoCleanup.get()) {
125
+ val (excludes, includes) = getPackagingOptionsForVariant(hermesEnabled)
126
+ variant.packaging.jniLibs.excludes.addAll(excludes)
127
+ variant.packaging.jniLibs.pickFirsts.addAll(includes)
128
+ }
129
+ }
130
+
131
+ fun getPackagingOptionsForVariant(hermesEnabled: Boolean): Pair<List<String>, List<String>> {
132
+ val excludes = mutableListOf<String>()
133
+ val includes = mutableListOf<String>()
134
+ if (hermesEnabled) {
135
+ excludes.add("**/libjsc.so")
136
+ excludes.add("**/libjscexecutor.so")
137
+ includes.add("**/libhermes.so")
138
+ includes.add("**/libhermes_executor.so")
139
+ } else {
140
+ excludes.add("**/libhermes.so")
141
+ excludes.add("**/libhermes_executor.so")
142
+ includes.add("**/libjsc.so")
143
+ includes.add("**/libjscexecutor.so")
144
+ }
145
+ return excludes to includes
146
+ }
147
+ }
@@ -0,0 +1,44 @@
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.utils
9
+
10
+ import java.io.File
11
+
12
+ internal object Os {
13
+
14
+ fun isWindows(): Boolean =
15
+ System.getProperty("os.name")?.lowercase()?.contains("windows") ?: false
16
+
17
+ fun isMac(): Boolean = System.getProperty("os.name")?.lowercase()?.contains("mac") ?: false
18
+
19
+ fun isLinuxAmd64(): Boolean {
20
+ val osNameMatch = System.getProperty("os.name")?.lowercase()?.contains("linux") ?: false
21
+ val archMatch = System.getProperty("os.arch")?.lowercase()?.contains("amd64") ?: false
22
+ return osNameMatch && archMatch
23
+ }
24
+
25
+ fun String.unixifyPath() =
26
+ this.replace('\\', '/').replace(":", "").let {
27
+ if (!it.startsWith("/")) {
28
+ "/$it"
29
+ } else {
30
+ it
31
+ }
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
+ }
44
+ }
@@ -0,0 +1,231 @@
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
+ @file:JvmName("PathUtils")
9
+
10
+ package com.facebook.react.utils
11
+
12
+ import com.facebook.react.ReactExtension
13
+ import com.facebook.react.model.ModelPackageJson
14
+ import com.facebook.react.utils.Os.cliPath
15
+ import java.io.File
16
+ import org.gradle.api.Project
17
+ import org.gradle.api.file.DirectoryProperty
18
+
19
+ /**
20
+ * Computes the entry file for React Native. The Algo follows this order:
21
+ * 1. The file pointed by the ENTRY_FILE env variable, if set.
22
+ * 2. The file provided by the `entryFile` config in the `reactApp` Gradle extension
23
+ * 3. The `index.android.js` file, if available.
24
+ * 4. Fallback to the `index.js` file.
25
+ *
26
+ * @param config The [ReactExtension] configured for this project
27
+ */
28
+ internal fun detectedEntryFile(config: ReactExtension, envVariableOverride: String? = null): File =
29
+ detectEntryFile(
30
+ entryFile = config.entryFile.orNull?.asFile,
31
+ reactRoot = config.root.get().asFile,
32
+ envVariableOverride = envVariableOverride)
33
+
34
+ /**
35
+ * Computes the CLI file for React Native. The Algo follows this order:
36
+ * 1. The path provided by the `cliFile` config in the `react {}` Gradle extension
37
+ * 2. The output of `node --print "require.resolve('react-native/cli');"` if not failing.
38
+ * 3. The `node_modules/react-native/cli.js` file if exists
39
+ * 4. Fails otherwise
40
+ */
41
+ internal fun detectedCliFile(config: ReactExtension): File =
42
+ detectCliFile(
43
+ reactNativeRoot = config.root.get().asFile,
44
+ preconfiguredCliFile = config.cliFile.asFile.orNull)
45
+
46
+ /**
47
+ * Computes the `hermesc` command location. The Algo follows this order:
48
+ * 1. The path provided by the `hermesCommand` config in the `react` Gradle extension
49
+ * 2. The file located in `node_modules/react-native/sdks/hermes/build/bin/hermesc`. This will be
50
+ * used if the user is building Hermes from source.
51
+ * 3. The file located in `node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc` where `%OS-BIN%`
52
+ * is substituted with the correct OS arch. This will be used if the user is using a precompiled
53
+ * hermes-engine package.
54
+ * 4. Fails otherwise
55
+ */
56
+ internal fun detectedHermesCommand(config: ReactExtension): String =
57
+ detectOSAwareHermesCommand(config.root.get().asFile, config.hermesCommand.get())
58
+
59
+ private fun detectEntryFile(
60
+ entryFile: File?,
61
+ reactRoot: File,
62
+ envVariableOverride: String? = null
63
+ ): File =
64
+ when {
65
+ envVariableOverride != null -> File(reactRoot, envVariableOverride)
66
+ entryFile != null -> entryFile
67
+ File(reactRoot, "index.android.js").exists() -> File(reactRoot, "index.android.js")
68
+ else -> File(reactRoot, "index.js")
69
+ }
70
+
71
+ private fun detectCliFile(reactNativeRoot: File, preconfiguredCliFile: File?): File {
72
+ // 1. preconfigured path
73
+ if (preconfiguredCliFile != null) {
74
+ if (preconfiguredCliFile.exists()) {
75
+ return preconfiguredCliFile
76
+ }
77
+ }
78
+
79
+ // 2. node module path
80
+ val nodeProcess =
81
+ Runtime.getRuntime()
82
+ .exec(
83
+ arrayOf("node", "--print", "require.resolve('react-native/cli');"),
84
+ emptyArray(),
85
+ reactNativeRoot)
86
+
87
+ val nodeProcessOutput = nodeProcess.inputStream.use { it.bufferedReader().readText().trim() }
88
+
89
+ if (nodeProcessOutput.isNotEmpty()) {
90
+ val nodeModuleCliJs = File(nodeProcessOutput)
91
+ if (nodeModuleCliJs.exists()) {
92
+ return nodeModuleCliJs
93
+ }
94
+ }
95
+
96
+ // 3. cli.js in the root folder
97
+ val rootCliJs = File(reactNativeRoot, "node_modules/react-native/cli.js")
98
+ if (rootCliJs.exists()) {
99
+ return rootCliJs
100
+ }
101
+
102
+ error(
103
+ """
104
+ Couldn't determine CLI location!
105
+
106
+ Please set `react { cliFile = file(...) }` inside your
107
+ build.gradle to the path of the react-native cli.js file.
108
+ This file typically resides in `node_modules/react-native/cli.js`
109
+ """
110
+ .trimIndent())
111
+ }
112
+
113
+ /**
114
+ * Computes the `hermesc` command location. The Algo follows this order:
115
+ * 1. The path provided by the `hermesCommand` config in the `react` Gradle extension
116
+ * 2. The file located in `node_modules/react-native/sdks/hermes/build/bin/hermesc`. This will be
117
+ * used if the user is building Hermes from source.
118
+ * 3. The file located in `node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc` where `%OS-BIN%`
119
+ * is substituted with the correct OS arch. This will be used if the user is using a precompiled
120
+ * hermes-engine package.
121
+ * 4. Fails otherwise
122
+ */
123
+ internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String): String {
124
+ // 1. If the project specifies a Hermes command, don't second guess it.
125
+ if (hermesCommand.isNotBlank()) {
126
+ val osSpecificHermesCommand =
127
+ if ("%OS-BIN%" in hermesCommand) {
128
+ hermesCommand.replace("%OS-BIN%", getHermesOSBin())
129
+ } else {
130
+ hermesCommand
131
+ }
132
+ return osSpecificHermesCommand
133
+ // Execution on Windows fails with / as separator
134
+ .replace('/', File.separatorChar)
135
+ }
136
+
137
+ // 2. If the project is building hermes-engine from source, use hermesc from there
138
+ val builtHermesc =
139
+ getBuiltHermescFile(projectRoot, System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR"))
140
+ if (builtHermesc.exists()) {
141
+ return builtHermesc.cliPath(projectRoot)
142
+ }
143
+
144
+ // 3. If the react-native contains a pre-built hermesc, use it.
145
+ val prebuiltHermesPath =
146
+ HERMESC_IN_REACT_NATIVE_DIR.plus(getHermesCBin())
147
+ .replace("%OS-BIN%", getHermesOSBin())
148
+ // Execution on Windows fails with / as separator
149
+ .replace('/', File.separatorChar)
150
+
151
+ val prebuiltHermes = File(projectRoot, prebuiltHermesPath)
152
+ if (prebuiltHermes.exists()) {
153
+ return prebuiltHermes.cliPath(projectRoot)
154
+ }
155
+
156
+ error(
157
+ "Couldn't determine Hermesc location. " +
158
+ "Please set `react.hermesCommand` to the path of the hermesc binary file. " +
159
+ "node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc")
160
+ }
161
+
162
+ /**
163
+ * Gets the location where Hermesc should be. If nothing is specified, built hermesc is assumed to
164
+ * be inside [HERMESC_BUILT_FROM_SOURCE_DIR]. Otherwise user can specify an override with
165
+ * [pathOverride], which is assumed to be an absolute path where Hermes source code is
166
+ * provided/built.
167
+ *
168
+ * @param projectRoot The root of the Project.
169
+ */
170
+ internal fun getBuiltHermescFile(projectRoot: File, pathOverride: String?) =
171
+ if (!pathOverride.isNullOrBlank()) {
172
+ File(pathOverride, "build/bin/${getHermesCBin()}")
173
+ } else {
174
+ File(projectRoot, HERMESC_BUILT_FROM_SOURCE_DIR.plus(getHermesCBin()))
175
+ }
176
+
177
+ internal fun getHermesCBin() = if (Os.isWindows()) "hermesc.exe" else "hermesc"
178
+
179
+ internal fun getHermesOSBin(): String {
180
+ if (Os.isWindows()) return "win64-bin"
181
+ if (Os.isMac()) return "osx-bin"
182
+ if (Os.isLinuxAmd64()) return "linux64-bin"
183
+ error(
184
+ "OS not recognized. Please set project.react.hermesCommand " +
185
+ "to the path of a working Hermes compiler.")
186
+ }
187
+
188
+ internal fun projectPathToLibraryName(projectPath: String): String =
189
+ projectPath
190
+ .split(':', '-', '_', '.')
191
+ .joinToString("") { token -> token.replaceFirstChar { it.uppercase() } }
192
+ .plus("Spec")
193
+
194
+ /**
195
+ * Function to look for the relevant `package.json`. We first look in the parent folder of this
196
+ * Gradle module (generally the case for library projects) or we fallback to looking into the `root`
197
+ * folder of a React Native project (generally the case for app projects).
198
+ */
199
+ internal fun findPackageJsonFile(project: Project, rootProperty: DirectoryProperty): File? {
200
+ val inParent = project.file("../package.json")
201
+ if (inParent.exists()) {
202
+ return inParent
203
+ }
204
+
205
+ val fromExtension = rootProperty.file("package.json").orNull?.asFile
206
+ if (fromExtension?.exists() == true) {
207
+ return fromExtension
208
+ }
209
+
210
+ return null
211
+ }
212
+
213
+ /**
214
+ * Function to look for the `package.json` and parse it. It returns a [ModelPackageJson] if found or
215
+ * null others.
216
+ *
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.
220
+ */
221
+ internal fun readPackageJsonFile(
222
+ project: Project,
223
+ rootProperty: DirectoryProperty
224
+ ): ModelPackageJson? {
225
+ val packageJson = findPackageJsonFile(project, rootProperty)
226
+ return packageJson?.let { JsonUtils.fromCodegenJson(it) }
227
+ }
228
+
229
+ private const val HERMESC_IN_REACT_NATIVE_DIR = "node_modules/react-native/sdks/hermesc/%OS-BIN%/"
230
+ private const val HERMESC_BUILT_FROM_SOURCE_DIR =
231
+ "node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/"
@@ -0,0 +1,55 @@
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.utils
9
+
10
+ import com.facebook.react.model.ModelPackageJson
11
+ import org.gradle.api.Project
12
+ import org.gradle.api.file.DirectoryProperty
13
+
14
+ internal object ProjectUtils {
15
+ internal val Project.isNewArchEnabled: Boolean
16
+ get() =
17
+ project.hasProperty("newArchEnabled") &&
18
+ project.property("newArchEnabled").toString().toBoolean()
19
+
20
+ const val HERMES_FALLBACK = true
21
+
22
+ internal val Project.isHermesEnabled: Boolean
23
+ get() =
24
+ if (project.hasProperty("hermesEnabled")) {
25
+ project.property("hermesEnabled").toString().lowercase().toBooleanStrictOrNull() ?: true
26
+ } else if (project.extensions.extraProperties.has("react")) {
27
+ @Suppress("UNCHECKED_CAST")
28
+ val reactMap = project.extensions.extraProperties.get("react") as? Map<String, Any?>
29
+ when (val enableHermesKey = reactMap?.get("enableHermes")) {
30
+ is Boolean -> enableHermesKey
31
+ is String -> enableHermesKey.lowercase().toBooleanStrictOrNull() ?: true
32
+ else -> HERMES_FALLBACK
33
+ }
34
+ } else {
35
+ HERMES_FALLBACK
36
+ }
37
+
38
+ internal fun Project.needsCodegenFromPackageJson(rootProperty: DirectoryProperty): Boolean {
39
+ val parsedPackageJson = readPackageJsonFile(this, rootProperty)
40
+ return needsCodegenFromPackageJson(parsedPackageJson)
41
+ }
42
+
43
+ internal fun Project.needsCodegenFromPackageJson(model: ModelPackageJson?): Boolean {
44
+ return model?.codegenConfig != null
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
+ }
55
+ }
@@ -0,0 +1,28 @@
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.utils
9
+
10
+ internal fun windowsAwareCommandLine(vararg args: Any): List<Any> =
11
+ windowsAwareCommandLine(args.toList())
12
+
13
+ internal fun windowsAwareCommandLine(args: List<Any>): List<Any> =
14
+ if (Os.isWindows()) {
15
+ listOf("cmd", "/c") + args
16
+ } else {
17
+ args
18
+ }
19
+
20
+ internal fun windowsAwareBashCommandLine(
21
+ vararg args: String,
22
+ bashWindowsHome: String? = null
23
+ ): List<String> =
24
+ if (Os.isWindows()) {
25
+ listOf(bashWindowsHome ?: "bash", "-c") + args
26
+ } else {
27
+ args.toList()
28
+ }