@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.
- package/README.md +16 -0
- package/build/libs/react-native-gradle-plugin.jar +0 -0
- package/build.gradle.kts +59 -0
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/gradlew +234 -0
- package/gradlew.bat +89 -0
- package/index.js +73 -0
- package/package.json +30 -0
- package/settings.gradle.kts +16 -0
- package/src/main/kotlin/com/facebook/react/ReactExtension.kt +151 -0
- package/src/main/kotlin/com/facebook/react/ReactPlugin.kt +212 -0
- package/src/main/kotlin/com/facebook/react/TaskConfiguration.kt +81 -0
- package/src/main/kotlin/com/facebook/react/internal/PrivateReactExtension.kt +56 -0
- package/src/main/kotlin/com/facebook/react/model/ModelCodegenConfig.kt +15 -0
- package/src/main/kotlin/com/facebook/react/model/ModelCodegenConfigAndroid.kt +10 -0
- package/src/main/kotlin/com/facebook/react/model/ModelPackageJson.kt +10 -0
- package/src/main/kotlin/com/facebook/react/tasks/BuildCodegenCLITask.kt +58 -0
- package/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt +200 -0
- package/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTask.kt +83 -0
- package/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt +82 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareBoostTask.kt +46 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareGlogTask.kt +79 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareJSCTask.kt +50 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareLibeventTask.kt +51 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PreparePrefabHeadersTask.kt +62 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/utils/PrefabPreprocessingEntry.kt +27 -0
- package/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt +54 -0
- package/src/main/kotlin/com/facebook/react/utils/BackwardCompatUtils.kt +48 -0
- package/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt +109 -0
- package/src/main/kotlin/com/facebook/react/utils/FileUtils.kt +20 -0
- package/src/main/kotlin/com/facebook/react/utils/JsonUtils.kt +21 -0
- package/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt +147 -0
- package/src/main/kotlin/com/facebook/react/utils/Os.kt +44 -0
- package/src/main/kotlin/com/facebook/react/utils/PathUtils.kt +231 -0
- package/src/main/kotlin/com/facebook/react/utils/ProjectUtils.kt +55 -0
- 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
|
+
}
|