mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Implement version parsing and connect to RNTester (#39502)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/39502 This diff adds the parsing of the package.json to retrieve the version of react native and it matches it against a regex to decide whether to enable or not the New Architecture. This change depends on [this CLI's PR](https://github.com/react-native-community/cli/pull/2076). ## Changelog: [Android][Added] - Parse RN Version to decide whether to enable the New Arch or not. Reviewed By: cortinico Differential Revision: D49270012 fbshipit-source-id: 5164a1ddd26f1822c0d717a7a9e2416ec38d78a2
This commit is contained in:
committed by
Facebook GitHub Bot
parent
55a0425fb2
commit
29adb8de98
+1
-1
@@ -64,7 +64,7 @@ class ReactPlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
configureReactNativeNdk(project, extension)
|
||||
configureBuildConfigFields(project)
|
||||
configureBuildConfigFields(project, extension)
|
||||
configureDevPorts(project)
|
||||
configureBackwardCompatibilityReactMap(project)
|
||||
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio
|
||||
val isDebuggableVariant =
|
||||
config.debuggableVariants.get().any { it.equals(variant.name, ignoreCase = true) }
|
||||
|
||||
configureNewArchPackagingOptions(project, variant)
|
||||
configureNewArchPackagingOptions(project, config, variant)
|
||||
configureJsEnginePackagingOptions(config, variant, isHermesEnabledInThisVariant)
|
||||
|
||||
if (!isDebuggableVariant) {
|
||||
|
||||
+5
-2
@@ -8,6 +8,7 @@
|
||||
package com.facebook.react.utils
|
||||
|
||||
import com.android.build.api.variant.AndroidComponentsExtension
|
||||
import com.facebook.react.ReactExtension
|
||||
import com.facebook.react.utils.ProjectUtils.isHermesEnabled
|
||||
import com.facebook.react.utils.ProjectUtils.isNewArchEnabled
|
||||
import org.gradle.api.Action
|
||||
@@ -17,13 +18,15 @@ import org.gradle.api.plugins.AppliedPlugin
|
||||
@Suppress("UnstableApiUsage")
|
||||
internal object AgpConfiguratorUtils {
|
||||
|
||||
fun configureBuildConfigFields(project: Project) {
|
||||
fun configureBuildConfigFields(project: Project, extension: ReactExtension) {
|
||||
val action =
|
||||
Action<AppliedPlugin> {
|
||||
project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext ->
|
||||
ext.buildFeatures.buildConfig = true
|
||||
ext.defaultConfig.buildConfigField(
|
||||
"boolean", "IS_NEW_ARCHITECTURE_ENABLED", project.isNewArchEnabled.toString())
|
||||
"boolean",
|
||||
"IS_NEW_ARCHITECTURE_ENABLED",
|
||||
project.isNewArchEnabled(extension).toString())
|
||||
ext.defaultConfig.buildConfigField(
|
||||
"boolean", "IS_HERMES_ENABLED", project.isHermesEnabled.toString())
|
||||
}
|
||||
|
||||
+4
-3
@@ -20,7 +20,7 @@ internal object NdkConfiguratorUtils {
|
||||
fun configureReactNativeNdk(project: Project, extension: ReactExtension) {
|
||||
project.pluginManager.withPlugin("com.android.application") {
|
||||
project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext ->
|
||||
if (!project.isNewArchEnabled) {
|
||||
if (!project.isNewArchEnabled(extension)) {
|
||||
// For Old Arch, we don't need to setup the NDK
|
||||
return@finalizeDsl
|
||||
}
|
||||
@@ -74,9 +74,10 @@ internal object NdkConfiguratorUtils {
|
||||
*/
|
||||
fun configureNewArchPackagingOptions(
|
||||
project: Project,
|
||||
variant: Variant,
|
||||
extension: ReactExtension,
|
||||
variant: Variant
|
||||
) {
|
||||
if (!project.isNewArchEnabled) {
|
||||
if (!project.isNewArchEnabled(extension)) {
|
||||
// For Old Arch, we set a pickFirst only on libraries that we know are
|
||||
// clashing with our direct dependencies (mainly FBJNI and Hermes).
|
||||
variant.packaging.jniLibs.pickFirsts.addAll(
|
||||
|
||||
+45
-6
@@ -7,6 +7,7 @@
|
||||
|
||||
package com.facebook.react.utils
|
||||
|
||||
import com.facebook.react.ReactExtension
|
||||
import com.facebook.react.model.ModelPackageJson
|
||||
import com.facebook.react.utils.KotlinStdlibCompatUtils.lowercaseCompat
|
||||
import com.facebook.react.utils.KotlinStdlibCompatUtils.toBooleanStrictOrNullCompat
|
||||
@@ -16,19 +17,22 @@ import com.facebook.react.utils.PropertyUtils.REACT_NATIVE_ARCHITECTURES
|
||||
import com.facebook.react.utils.PropertyUtils.SCOPED_HERMES_ENABLED
|
||||
import com.facebook.react.utils.PropertyUtils.SCOPED_NEW_ARCH_ENABLED
|
||||
import com.facebook.react.utils.PropertyUtils.SCOPED_REACT_NATIVE_ARCHITECTURES
|
||||
import java.io.File
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
|
||||
internal object ProjectUtils {
|
||||
internal val Project.isNewArchEnabled: Boolean
|
||||
get() =
|
||||
(project.hasProperty(NEW_ARCH_ENABLED) &&
|
||||
project.property(NEW_ARCH_ENABLED).toString().toBoolean()) ||
|
||||
(project.hasProperty(SCOPED_NEW_ARCH_ENABLED) &&
|
||||
project.property(SCOPED_NEW_ARCH_ENABLED).toString().toBoolean())
|
||||
|
||||
const val HERMES_FALLBACK = true
|
||||
|
||||
internal fun Project.isNewArchEnabled(extension: ReactExtension): Boolean {
|
||||
return (project.hasProperty(NEW_ARCH_ENABLED) &&
|
||||
project.property(NEW_ARCH_ENABLED).toString().toBoolean()) ||
|
||||
(project.hasProperty(SCOPED_NEW_ARCH_ENABLED) &&
|
||||
project.property(SCOPED_NEW_ARCH_ENABLED).toString().toBoolean()) ||
|
||||
shouldEnableNewArchForReactNativeVersion(project.reactNativeDir(extension))
|
||||
}
|
||||
|
||||
internal val Project.isHermesEnabled: Boolean
|
||||
get() =
|
||||
if (project.hasProperty(HERMES_ENABLED) || project.hasProperty(SCOPED_HERMES_ENABLED)) {
|
||||
@@ -75,4 +79,39 @@ internal object ProjectUtils {
|
||||
}
|
||||
return architectures
|
||||
}
|
||||
|
||||
internal fun Project.reactNativeDir(extension: ReactExtension): String =
|
||||
extension.reactNativeDir.get().asFile.absolutePath
|
||||
|
||||
internal fun shouldEnableNewArchForReactNativeVersion(reactNativeDir: String): Boolean {
|
||||
val packageJsonFile = File(reactNativeDir, "package.json")
|
||||
if (!packageJsonFile.exists()) {
|
||||
return false
|
||||
}
|
||||
|
||||
val rnPackageJson = JsonUtils.fromPackageJson(packageJsonFile)
|
||||
if (rnPackageJson == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
// This regex describe the version syntax for React Native in the shape of
|
||||
// major.minor.patch[-<prerelease>[[-.]k]]
|
||||
// Where
|
||||
// major is a number
|
||||
// minor is a number
|
||||
// patch is a number
|
||||
// <prerelease>[-.]k is optional, but if present is preceeded by a `-`
|
||||
// the <prerelease> tag is a string.
|
||||
// it can be followed by `-` or `.` and k is a number.
|
||||
val regex = """^(\d+)\.(\d+)\.(\d+)(?:-(\w+(?:[-.]\d+)?))?$""".toRegex()
|
||||
|
||||
val matchResult = regex.find(rnPackageJson.version)
|
||||
|
||||
if (matchResult == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
val major = matchResult.groupValues[1].toInt()
|
||||
return major > 0 && major < 1000
|
||||
}
|
||||
}
|
||||
|
||||
+117
-4
@@ -27,28 +27,141 @@ class ProjectUtilsTest {
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_returnsFalseByDefault() {
|
||||
assertFalse(createProject().isNewArchEnabled)
|
||||
val project = createProject()
|
||||
val extension = TestReactExtension(project)
|
||||
assertFalse(createProject().isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_withDisabled_returnsFalse() {
|
||||
val project = createProject()
|
||||
project.extensions.extraProperties.set("newArchEnabled", "false")
|
||||
assertFalse(project.isNewArchEnabled)
|
||||
val extension = TestReactExtension(project)
|
||||
assertFalse(project.isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_withEnabled_returnsTrue() {
|
||||
val project = createProject()
|
||||
project.extensions.extraProperties.set("newArchEnabled", "true")
|
||||
assertTrue(project.isNewArchEnabled)
|
||||
val extension = TestReactExtension(project)
|
||||
assertTrue(project.isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_withInvalid_returnsFalse() {
|
||||
val project = createProject()
|
||||
project.extensions.extraProperties.set("newArchEnabled", "¯\\_(ツ)_/¯")
|
||||
assertFalse(project.isNewArchEnabled)
|
||||
val extension = TestReactExtension(project)
|
||||
assertFalse(project.isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_withRNVersion0_returnFalse() {
|
||||
val project = createProject()
|
||||
val extension = TestReactExtension(project)
|
||||
File(tempFolder.root, "package.json").apply {
|
||||
writeText(
|
||||
// language=json
|
||||
"""
|
||||
{
|
||||
"version": "0.73.0"
|
||||
}
|
||||
"""
|
||||
.trimIndent())
|
||||
}
|
||||
extension.reactNativeDir.set(tempFolder.root)
|
||||
assertFalse(project.isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_withRNVersion1_returnTrue() {
|
||||
val project = createProject()
|
||||
val extension = TestReactExtension(project)
|
||||
File(tempFolder.root, "package.json").apply {
|
||||
writeText(
|
||||
// language=json
|
||||
"""
|
||||
{
|
||||
"version": "1.2.3"
|
||||
}
|
||||
"""
|
||||
.trimIndent())
|
||||
}
|
||||
extension.reactNativeDir.set(tempFolder.root)
|
||||
assertTrue(project.isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_withRNVersion1PrereleaseString_returnTrue() {
|
||||
val project = createProject()
|
||||
val extension = TestReactExtension(project)
|
||||
File(tempFolder.root, "package.json").apply {
|
||||
writeText(
|
||||
// language=json
|
||||
"""
|
||||
{
|
||||
"version": "1.2.3-prealpha0"
|
||||
}
|
||||
"""
|
||||
.trimIndent())
|
||||
}
|
||||
extension.reactNativeDir.set(tempFolder.root)
|
||||
assertTrue(project.isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_withRNVersion1PrereleaseStringDotNumber_returnTrue() {
|
||||
val project = createProject()
|
||||
val extension = TestReactExtension(project)
|
||||
File(tempFolder.root, "package.json").apply {
|
||||
writeText(
|
||||
// language=json
|
||||
"""
|
||||
{
|
||||
"version": "1.2.3-prealpha.0"
|
||||
}
|
||||
"""
|
||||
.trimIndent())
|
||||
}
|
||||
extension.reactNativeDir.set(tempFolder.root)
|
||||
assertTrue(project.isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_withRNVersion1PrereleaseStringDashNumber_returnTrue() {
|
||||
val project = createProject()
|
||||
val extension = TestReactExtension(project)
|
||||
File(tempFolder.root, "package.json").apply {
|
||||
writeText(
|
||||
// language=json
|
||||
"""
|
||||
{
|
||||
"version": "1.2.3-prealpha-0"
|
||||
}
|
||||
"""
|
||||
.trimIndent())
|
||||
}
|
||||
extension.reactNativeDir.set(tempFolder.root)
|
||||
assertTrue(project.isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNewArchEnabled_withRNVersion1000_returnFalse() {
|
||||
val project = createProject()
|
||||
val extension = TestReactExtension(project)
|
||||
File(tempFolder.root, "package.json").apply {
|
||||
writeText(
|
||||
// language=json
|
||||
"""
|
||||
{
|
||||
"version": "1000.0.0"
|
||||
}
|
||||
"""
|
||||
.trimIndent())
|
||||
}
|
||||
extension.reactNativeDir.set(tempFolder.root)
|
||||
assertFalse(project.isNewArchEnabled(extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -5,12 +5,35 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
plugins {
|
||||
id("com.facebook.react")
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
}
|
||||
|
||||
def reactNativeVersionRequireNewArchEnabled(reactNativeDirPath) {
|
||||
def reactNativePackageJson = "$reactNativeDirPath/package.json"
|
||||
def slurper = new JsonSlurper()
|
||||
def jsonData = slurper.parse(new File(reactNativePackageJson))
|
||||
def rnVersion = jsonData.version
|
||||
def regexPattern = /^(\d+)\.(\d+)\.(\d+)(?:-(\w+(?:[-.]\d+)?))?$/
|
||||
|
||||
|
||||
if (rnVersion =~ regexPattern) {
|
||||
def result = (rnVersion =~ regexPattern).findAll().first()
|
||||
|
||||
def major = result[1].toInteger()
|
||||
if (major > 0 && major < 1000) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
def reactNativeDirPath = "$rootDir/packages/react-native"
|
||||
def isNewArchEnabled = project.property("newArchEnabled") == "true" || reactNativeVersionRequireNewArchEnabled(reactNativeDirPath)
|
||||
/**
|
||||
* 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.
|
||||
@@ -20,11 +43,11 @@ react {
|
||||
// The root of your project, i.e. where "package.json" lives. Default is '..'
|
||||
root = file("../../")
|
||||
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
|
||||
reactNativeDir = file("$rootDir/packages/react-native")
|
||||
reactNativeDir = file(reactNativeDirPath)
|
||||
// The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
|
||||
codegenDir = file("$rootDir/node_modules/@react-native/codegen")
|
||||
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
|
||||
cliFile = file("$rootDir/packages/react-native/cli.js")
|
||||
cliFile = file("$reactNativeDirPath/cli.js")
|
||||
|
||||
/* Variants */
|
||||
// The list of variants to that are debuggable. For those we're going to
|
||||
@@ -54,7 +77,7 @@ react {
|
||||
|
||||
/* Hermes Commands */
|
||||
// The hermes compiler command to run. By default it is 'hermesc'
|
||||
hermesCommand = "$rootDir/packages/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc"
|
||||
hermesCommand = "$reactNativeDirPath/ReactAndroid/hermes-engine/build/hermes/bin/hermesc"
|
||||
enableHermesOnlyInVariants = ["hermesDebug", "hermesRelease"]
|
||||
}
|
||||
|
||||
@@ -148,7 +171,7 @@ android {
|
||||
java {
|
||||
// SampleTurboModule.
|
||||
srcDirs += [
|
||||
"$rootDir/packages/react-native/ReactCommon/react/nativemodule/samples/platform/android",
|
||||
"$reactNativeDirPath/ReactCommon/react/nativemodule/samples/platform/android",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -172,7 +195,7 @@ android {
|
||||
cmake {
|
||||
// RN Tester is doing custom linking of C++ libraries therefore needs
|
||||
// a dedicated CMakeLists.txt file.
|
||||
if (project.property("newArchEnabled") == "true") {
|
||||
if (isNewArchEnabled) {
|
||||
path("src/main/jni/CMakeLists.txt")
|
||||
}
|
||||
}
|
||||
@@ -189,7 +212,7 @@ afterEvaluate {
|
||||
// As we're building 4 native flavors in parallel, there is clash on the `.cxx/Debug` and
|
||||
// `.cxx/Release` folder where the CMake intermediates are stored.
|
||||
// We fixing this by instructing Gradle to always mergeLibs after they've been built.
|
||||
if (project.property("newArchEnabled") == "true") {
|
||||
if (isNewArchEnabled) {
|
||||
mergeHermesDebugNativeLibs.mustRunAfter(externalNativeBuildJscDebug)
|
||||
mergeHermesReleaseNativeLibs.mustRunAfter(externalNativeBuildJscRelease)
|
||||
mergeJscDebugNativeLibs.mustRunAfter(externalNativeBuildHermesDebug)
|
||||
|
||||
Reference in New Issue
Block a user