Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RNGP - Autolinking. Add support for linking projects. #44799

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ project.xcworkspace

# Gradle
/build/
/packages/react-native-gradle-plugin/build/
/packages/rn-tester/build
/packages/rn-tester/android/app/.cxx/
/packages/rn-tester/android/app/build/
Expand Down
6 changes: 3 additions & 3 deletions packages/helloworld/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ react {
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]

/* Autolinking */
autolinkLibrariesWithApp()
}

/**
Expand Down Expand Up @@ -121,6 +124,3 @@ dependencies {
implementation jscFlavor
}
}

// TODO: This needs to use the new autolinking code in the gradle-plugin instead
// apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
package com.helloworld

import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.PackageList2
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
Expand All @@ -23,7 +23,7 @@ class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
PackageList2(this).packages.apply {
// Packages that cannot be autolinked yet can be added manually here, for example:
// add(MyReactNativePackage())
}
Expand Down
7 changes: 6 additions & 1 deletion packages/helloworld/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
* LICENSE file in the root directory of this source tree.
*/

// Autolinking has now moved into the React Native Gradle Plugin
import com.facebook.react.ReactSettingsExtension
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }

rootProject.name = 'HelloWorld'
include ':app'
// Autolinking has now moved into the React Native Gradle Plugin
includeBuild('../../react-native-gradle-plugin')
4 changes: 4 additions & 0 deletions packages/react-native-gradle-plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
build/
app-plugin/build/
settings-plugin/build/
shared/build/
75 changes: 1 addition & 74 deletions packages/react-native-gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,80 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import org.gradle.api.internal.classpath.ModuleRegistry
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.configurationcache.extensions.serviceOf
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.jvm).apply(false)
id("java-gradle-plugin")
}

repositories {
google()
mavenCentral()
}

gradlePlugin {
plugins {
create("react") {
id = "com.facebook.react"
implementationClass = "com.facebook.react.ReactPlugin"
}
create("reactrootproject") {
id = "com.facebook.react.rootproject"
implementationClass = "com.facebook.react.ReactRootProjectPlugin"
}
}
}

group = "com.facebook.react"

dependencies {
implementation(gradleApi())

// The KGP/AGP version is defined by React Native Gradle plugin.
// Therefore we specify an implementation dep rather than a compileOnly.
implementation(libs.kotlin.gradle.plugin)
implementation(libs.android.gradle.plugin)

implementation(libs.gson)
implementation(libs.guava)
implementation(libs.javapoet)

testImplementation(libs.junit)

testRuntimeOnly(
files(
serviceOf<ModuleRegistry>()
.getModule("gradle-tooling-api-builders")
.classpath
.asFiles
.first()))
}

// We intentionally don't build for Java 17 as users will see a cryptic bytecode version
// error first. Instead we produce a Java 11-compatible Gradle Plugin, so that AGP can print their
// nice message showing that JDK 11 (or 17) is required first
java { targetCompatibility = JavaVersion.VERSION_11 }

kotlin { jvmToolchain(17) }

tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
apiVersion = "1.6"
// See comment above on JDK 11 support
jvmTarget = "11"
allWarningsAsErrors = true
}
}

tasks.withType<Test>().configureEach {
testLogging {
exceptionFormat = TestExceptionFormat.FULL
showExceptions = true
showCauses = true
showStackTraces = true
}
}
6 changes: 4 additions & 2 deletions packages/react-native-gradle-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
"gradle",
"gradlew",
"gradlew.bat",
"src/main",
"README.md"
"README.md",
"react-native-gradle-plugin",
"settings-plugin",
"shared"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# React Native Gradle Plugin

This plugin is used by React Native Apps to configure themselves.

NOTE: It's important that this folder is called `react-native-gradle-plugin` as it's used
by users in their `build.gradle` file as follows:

```gradle
buildscript {
// ...
dependencies {
classpath("com.facebook.react:react-native-gradle-plugin")
}
}
```

The name of the artifact is imposed by the folder name.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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.
*/

import org.gradle.api.internal.classpath.ModuleRegistry
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.configurationcache.extensions.serviceOf
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
alias(libs.plugins.kotlin.jvm)
id("java-gradle-plugin")
}

repositories {
google()
mavenCentral()
}

gradlePlugin {
plugins {
create("react") {
id = "com.facebook.react"
implementationClass = "com.facebook.react.ReactPlugin"
}
create("reactrootproject") {
id = "com.facebook.react.rootproject"
implementationClass = "com.facebook.react.ReactRootProjectPlugin"
}
}
}

group = "com.facebook.react"

dependencies {
implementation(project(":shared"))

implementation(gradleApi())

// The KGP/AGP version is defined by React Native Gradle plugin.
// Therefore we specify an implementation dep rather than a compileOnly.
implementation(libs.kotlin.gradle.plugin)
implementation(libs.android.gradle.plugin)

implementation(libs.gson)
implementation(libs.guava)
implementation(libs.javapoet)

testImplementation(libs.junit)

testRuntimeOnly(
files(
serviceOf<ModuleRegistry>()
.getModule("gradle-tooling-api-builders")
.classpath
.asFiles
.first()))
}

// We intentionally don't build for Java 17 as users will see a cryptic bytecode version
// error first. Instead we produce a Java 11-compatible Gradle Plugin, so that AGP can print their
// nice message showing that JDK 11 (or 17) is required first
java { targetCompatibility = JavaVersion.VERSION_11 }

kotlin { jvmToolchain(17) }

tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
apiVersion = "1.6"
// See comment above on JDK 11 support
jvmTarget = "11"
allWarningsAsErrors = true
}
}

tasks.withType<Test>().configureEach {
testLogging {
exceptionFormat = TestExceptionFormat.FULL
showExceptions = true
showCauses = true
showStackTraces = true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@

package com.facebook.react

import com.facebook.react.utils.JsonUtils
import com.facebook.react.utils.projectPathToLibraryName
import java.io.File
import javax.inject.Inject
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property

abstract class ReactExtension @Inject constructor(project: Project) {
abstract class ReactExtension @Inject constructor(val project: Project) {

private val objects = project.objects

Expand Down Expand Up @@ -149,34 +150,54 @@ abstract class ReactExtension @Inject constructor(project: Project) {
val codegenJavaPackageName: Property<String> =
objects.property(String::class.java).convention("com.facebook.fbreact.specs")

/** Auto-linking Config */
/** Auto-linking Utils */

/**
* Location of the JSON file used to configure autolinking. This file is the output of the
* `@react-native-community/cli` config command.
* Utility function to autolink libraries to the app.
*
* If not specified, RNGP will just invoke whatever you pass as [autolinkConfigCommand].
*/
val autolinkConfigFile: RegularFileProperty = objects.fileProperty()

/**
* The command to invoke as source of truth for the autolinking configuration. Default is `["npx",
* "@react-native-community/cli", "config"]`.
*/
val autolinkConfigCommand: ListProperty<String> =
objects
.listProperty(String::class.java)
.convention(listOf("npx", "@react-native-community/cli", "config"))

/**
* Location of the lock files used to consider whether autolinking [autolinkConfigCommand] should
* re-execute or not. If file collection is unchanged, the autolinking command will not be
* re-executed.
*
* If not specified, RNGP will just look for both yarn.lock and package.lock in the [root] folder.
*/
val autolinkLockFiles: Property<FileCollection> =
objects
.property(FileCollection::class.java)
.convention(root.files("../yarn.lock", "../package-lock.json"))
* This function will read the autolinking configuration file and add Gradle dependencies to the
* app. This function should be invoked inside the react {} block in the app's build.gradle and is
* necessary for libraries to be linked correctly.
*/
fun autolinkLibrariesWithApp() {
val inputFile =
project.rootProject.layout.buildDirectory
.file("generated/autolinking/autolinking.json")
.get()
.asFile
val dependenciesToApply = getGradleDependenciesToApply(inputFile)
dependenciesToApply.forEach { (configuration, path) ->
project.dependencies.add(configuration, project.dependencies.project(mapOf("path" to path)))
}
}

companion object {
/**
* Util function to construct a list of Gradle Configuration <-> Project name pairs for
* autolinking. Pairs looks like: "implementation" -> ":react-native_oss-library-example"
*
* They will be applied to the Gradle project for linking the libraries.
*
* @param inputFile The file to read the autolinking configuration from.
* @return A list of Gradle Configuration <-> Project name pairs.
*/
internal fun getGradleDependenciesToApply(inputFile: File): MutableList<Pair<String, String>> {
val model = JsonUtils.fromAutolinkingConfigJson(inputFile)
val result = mutableListOf<Pair<String, String>>()
model?.dependencies?.values?.forEach { deps ->
val nameCleansed = deps.nameCleansed
val dependencyConfiguration = deps.platforms?.android?.dependencyConfiguration
val buildTypes = deps.platforms?.android?.buildTypes ?: emptyList()
if (buildTypes.isEmpty()) {
result.add((dependencyConfiguration ?: "implementation") to ":$nameCleansed")
} else {
buildTypes.forEach { buildType ->
result.add(
(dependencyConfiguration ?: "${buildType}Implementation") to ":$nameCleansed")
}
}
}
return result
}
}
}
Loading
Loading