Skip to content

Commit

Permalink
RNGP - Various improvements needed for 3rd party libs (facebook#35496)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#35496

This commit includes a series of fixes needed for better integration with libraries for 0.71:
- I've added an `android/README.md` file as some libraries were failing the build if the folder was missing
- RNGP now applies dep substitution on app and all the libraries project
- RNGP now adds repositories on app and all the libraries project
- I've removed the maven local repo to the `/android` folder as now is empty
- I've fixed the path for the JSC repo for Windows users
- I've added a bit of backward compat by re-adding an empty `project.react.ext` block that libraries might read from.
- I've removed `codegenDir` from the `GenerateCodegenArtifactsTask` which was unused.

Changelog:
[Internal] [Changed] - RNGP - Various improvements needed for 3rd party libs

Reviewed By: cipolleschi

Differential Revision: D41549489

fbshipit-source-id: 2252da0180ac24fd3fe5a55300527da6781f0f8c
  • Loading branch information
cortinico authored and OlimpiaZurek committed May 22, 2023
1 parent 94fe9c5 commit b30ca76
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 69 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ buck-out
.gradle
local.properties
*.iml
/android/
/android/*
!/android/README.md

# Node
node_modules
Expand Down
21 changes: 21 additions & 0 deletions android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The `/android` folder inside `react-native`

Starting from React Native 0.71, we're not shipping the `/android` folder inside the React Native NPM package
anymore due to sizing constraints on NPM. The Android artifacts are distributed via Maven Central.
You can read more about it in this RFC:
https://github.com/react-native-community/discussions-and-proposals/pull/508

If you're a library author and you're manipulating the React Native .aar files, to extract headers,
extract `.so` files or do anything with it, you're probably doing something wrong. React Native
0.71 ships with all the necessary logic to let you consume it transparently by just using:

```
implementation("com.facebook.react:react-android")
// or to keep backward compatibility with older versions of React Native:
implementation("com.facebook.react:react-native:+")
```

You should consider refactoring your library code not to unzip/manipulate the React Native .aar files.

This README.md file is kept in this folder as some libraries are checking the existence of the `/android` folder
and failing user builds if the folder is missing.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.facebook.react.tasks.GenerateCodegenArtifactsTask
import com.facebook.react.tasks.GenerateCodegenSchemaTask
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFields
import com.facebook.react.utils.AgpConfiguratorUtils.configureDevPorts
import com.facebook.react.utils.BackwardCompatUtils.configureBackwardCompatibilityReactMap
import com.facebook.react.utils.DependencyUtils.configureDependencies
import com.facebook.react.utils.DependencyUtils.configureRepositories
import com.facebook.react.utils.DependencyUtils.readVersionString
Expand Down Expand Up @@ -46,6 +47,7 @@ class ReactPlugin : Plugin<Project> {
configureReactNativeNdk(project, extension)
configureBuildConfigFields(project)
configureDevPorts(project)
configureBackwardCompatibilityReactMap(project)

project.extensions.getByType(AndroidComponentsExtension::class.java).apply {
onVariants(selector().all()) { variant ->
Expand Down Expand Up @@ -134,7 +136,6 @@ class ReactPlugin : Plugin<Project> {
it.dependsOn(generateCodegenSchemaTask)
it.reactNativeDir.set(extension.reactNativeDir)
it.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)
it.codegenDir.set(extension.codegenDir)
it.generatedSrcDir.set(generatedSrcDir)
it.packageJsonFile.set(findPackageJsonFile(project, extension))
it.codegenJavaPackageName.set(extension.codegenJavaPackageName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ abstract class GenerateCodegenArtifactsTask : Exec() {

@get:Internal abstract val reactNativeDir: DirectoryProperty

@get:Internal abstract val codegenDir: DirectoryProperty

@get:Internal abstract val generatedSrcDir: DirectoryProperty

@get:InputFile abstract val packageJsonFile: RegularFileProperty
Expand All @@ -38,10 +36,6 @@ abstract class GenerateCodegenArtifactsTask : Exec() {

@get:Input abstract val libraryName: Property<String>

@get:InputFile
val combineJsToSchemaCli: Provider<RegularFile> =
codegenDir.file("lib/cli/combine/combine-js-to-schema-cli.js")

@get:InputFile
val generatedSchemaFile: Provider<RegularFile> = generatedSrcDir.file("schema.json")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.utils

import java.util.*
import org.gradle.api.Project

internal object BackwardCompatUtils {

fun configureBackwardCompatibilityReactMap(project: Project) {
if (project.extensions.extraProperties.has("react")) {
@Suppress("UNCHECKED_CAST")
val reactMap =
project.extensions.extraProperties.get("react") as? Map<String, Any?> ?: mapOf()
if (reactMap.isNotEmpty()) {
project.logger.error(
"""
********************************************************************************
ERROR: Using old project.ext.react configuration.
We identified that your project is using a old configuration block as:
project.ext.react = [
// ...
]
You should migrate to the new configuration:
react {
// ...
}
You can find documentation inside `android/app/build.gradle` on how to use it.
********************************************************************************
"""
.trimIndent())
}
}

// We set an empty react[] map so if a library is reading it, they will find empty values.
project.extensions.extraProperties.set("react", mapOf<String, String>())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,44 +15,57 @@ import org.gradle.api.artifacts.repositories.MavenArtifactRepository

internal object DependencyUtils {

/**
* This method takes care of configuring the repositories{} block for both the app and all the 3rd
* party libraries which are auto-linked.
*/
fun configureRepositories(project: Project, reactNativeDir: File) {
with(project) {
if (hasProperty("REACT_NATIVE_MAVEN_LOCAL_REPO")) {
mavenRepoFromUrl("file://${property("REACT_NATIVE_MAVEN_LOCAL_REPO")}")
project.rootProject.allprojects { eachProject ->
with(eachProject) {
if (hasProperty("REACT_NATIVE_MAVEN_LOCAL_REPO")) {
mavenRepoFromUrl("file://${property("REACT_NATIVE_MAVEN_LOCAL_REPO")}")
}
// We add the snapshot for users on nightlies.
mavenRepoFromUrl("https://oss.sonatype.org/content/repositories/snapshots/")
repositories.mavenCentral()
// Android JSC is installed from npm
mavenRepoFromUrl(
"file://${reactNativeDir}${File.separator}..${File.separator}jsc-android${File.separator}dist")
repositories.google()
mavenRepoFromUrl("https://www.jitpack.io")
}
// We add the snapshot for users on nightlies.
mavenRepoFromUrl("https://oss.sonatype.org/content/repositories/snapshots/")
repositories.mavenCentral()
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
mavenRepoFromUrl("file://${reactNativeDir}/android")
// Android JSC is installed from npm
mavenRepoFromUrl("file://${reactNativeDir}/../jsc-android/dist")
repositories.google()
mavenRepoFromUrl("https://www.jitpack.io")
}
}

/**
* This method takes care of configuring the resolution strategy for both the app and all the 3rd
* party libraries which are auto-linked. Specifically it takes care of:
* - Forcing the react-android/hermes-android version to the one specified in the package.json
* - Substituting `react-native` with `react-android` and `hermes-engine` with `hermes-android`.
*/
fun configureDependencies(project: Project, versionString: String) {
if (versionString.isBlank()) return
project.configurations.all { configuration ->
// Here we set a dependencySubstitution for both react-native and hermes-engine as those
// coordinates are voided due to https://github.com/facebook/react-native/issues/35210
// This allows users to import libraries that are still using
// implementation("com.facebook.react:react-native:+") and resolve the right dependency.
configuration.resolutionStrategy.dependencySubstitution {
it.substitute(it.module("com.facebook.react:react-native"))
.using(it.module("com.facebook.react:react-android:${versionString}"))
.because(
"The react-native artifact was deprecated in favor of react-android due to https://github.com/facebook/react-native/issues/35210.")
it.substitute(it.module("com.facebook.react:hermes-engine"))
.using(it.module("com.facebook.react:hermes-android:${versionString}"))
.because(
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210.")
project.rootProject.allprojects { eachProject ->
eachProject.configurations.all { configuration ->
// Here we set a dependencySubstitution for both react-native and hermes-engine as those
// coordinates are voided due to https://github.com/facebook/react-native/issues/35210
// This allows users to import libraries that are still using
// implementation("com.facebook.react:react-native:+") and resolve the right dependency.
configuration.resolutionStrategy.dependencySubstitution {
it.substitute(it.module("com.facebook.react:react-native"))
.using(it.module("com.facebook.react:react-android:${versionString}"))
.because(
"The react-native artifact was deprecated in favor of react-android due to https://github.com/facebook/react-native/issues/35210.")
it.substitute(it.module("com.facebook.react:hermes-engine"))
.using(it.module("com.facebook.react:hermes-android:${versionString}"))
.because(
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210.")
}
configuration.resolutionStrategy.force(
"com.facebook.react:react-android:${versionString}",
"com.facebook.react:hermes-android:${versionString}",
)
}
configuration.resolutionStrategy.force(
"com.facebook.react:react-android:${versionString}",
"com.facebook.react:hermes-android:${versionString}",
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,16 @@ class GenerateCodegenArtifactsTaskTest {
val codegenDir = tempFolder.newFolder("codegen")
val outputDir = tempFolder.newFolder("output")

val task =
createTestTask<GenerateCodegenArtifactsTask> {
it.codegenDir.set(codegenDir)
it.generatedSrcDir.set(outputDir)
}
val task = createTestTask<GenerateCodegenArtifactsTask> { it.generatedSrcDir.set(outputDir) }

assertEquals(
File(codegenDir, "lib/cli/combine/combine-js-to-schema-cli.js"),
task.combineJsToSchemaCli.get().asFile)
assertEquals(File(outputDir, "schema.json"), task.generatedSchemaFile.get().asFile)
}

@Test
fun generateCodegenSchema_outputFile_isSetCorrectly() {
val codegenDir = tempFolder.newFolder("codegen")
val outputDir = tempFolder.newFolder("output")

val task =
createTestTask<GenerateCodegenArtifactsTask> {
it.codegenDir.set(codegenDir)
it.generatedSrcDir.set(outputDir)
}
val task = createTestTask<GenerateCodegenArtifactsTask> { it.generatedSrcDir.set(outputDir) }

assertEquals(File(outputDir, "java"), task.generatedJavaFiles.get().asFile)
assertEquals(File(outputDir, "jni"), task.generatedJniFiles.get().asFile)
Expand Down Expand Up @@ -80,13 +68,11 @@ class GenerateCodegenArtifactsTaskTest {
@WithOs(OS.LINUX)
fun setupCommandLine_willSetupCorrectly() {
val reactNativeDir = tempFolder.newFolder("node_modules/react-native/")
val codegenDir = tempFolder.newFolder("codegen")
val outputDir = tempFolder.newFolder("output")

val task =
createTestTask<GenerateCodegenArtifactsTask> {
it.reactNativeDir.set(reactNativeDir)
it.codegenDir.set(codegenDir)
it.generatedSrcDir.set(outputDir)
it.nodeExecutableAndArgs.set(listOf("--verbose"))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.utils

import com.facebook.react.tests.createProject
import com.facebook.react.utils.BackwardCompatUtils.configureBackwardCompatibilityReactMap
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder

class BackwardCompatUtilsTest {

@get:Rule val tempFolder = TemporaryFolder()

@Test
fun configureBackwardCompatibilityReactMap_addsEmptyReactMap() {
val project = createProject()

configureBackwardCompatibilityReactMap(project)

assertTrue(project.extensions.extraProperties.has("react"))
@Suppress("UNCHECKED_CAST")
assertTrue((project.extensions.extraProperties.get("react") as Map<String, Any?>).isEmpty())
}

@Test
fun configureBackwardCompatibilityReactMap_withExistingMapSetByUser_wipesTheMap() {
val project = createProject()
project.extensions.extraProperties.set("react", mapOf("enableHermes" to true))

configureBackwardCompatibilityReactMap(project)

assertTrue(project.extensions.extraProperties.has("react"))
@Suppress("UNCHECKED_CAST")
assertTrue((project.extensions.extraProperties.get("react") as Map<String, Any?>).isEmpty())
}
}
Loading

0 comments on commit b30ca76

Please sign in to comment.