Skip to content
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
12 changes: 1 addition & 11 deletions ReactAndroid/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,12 @@
* LICENSE file in the root directory of this source tree.
*/

buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.hasProperty("kotlinVersion") ? rootProject.ext.kotlinVersion : KOTLIN_VERSION}"
}
}

plugins {
id("com.android.library")
id("com.facebook.react")
id("de.undercouch.download")
id("maven-publish")
id("org.jetbrains.kotlin.android")
}

import com.facebook.react.tasks.internal.*
Expand Down Expand Up @@ -672,12 +667,7 @@ react {
// TODO: The library name is chosen for parity with Fabric components & iOS
// This should be changed to a more generic name, e.g. `ReactCoreSpec`.
libraryName = "rncore"
root = file("..")
jsRootDir = file("../Libraries")
reactNativeDir = file("$projectDir/..")
// We search for the codegen in either one of the `node_modules` folder or in the
// root packages folder (that's for when we build from source without calling `yarn install`).
codegenDir = file(findNodeModulePath(projectDir, "@react-native/codegen") ?: "../packages/react-native-codegen/")
}

apply plugin: "org.jetbrains.kotlin.android"
Expand Down
3 changes: 0 additions & 3 deletions ReactAndroid/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,5 @@ FOLLY_VERSION=2021.07.22.00
GLOG_VERSION=0.3.5
LIBEVENT_VERSION=2.1.12

# Plugins Versions
KOTLIN_VERSION=1.6.10

android.useAndroidX=true
android.enableJetifier=true
29 changes: 8 additions & 21 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
* LICENSE file in the root directory of this source tree.
*/

plugins { id("io.github.gradle-nexus.publish-plugin") version "1.1.0" }
plugins {
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
id("com.android.library") version "7.4.1" apply false
id("com.android.application") version "7.4.1" apply false
id("de.undercouch.download") version "5.0.1" apply false
kotlin("android") version "1.6.10" apply false
}

val reactAndroidProperties = java.util.Properties()

Expand All @@ -25,19 +31,6 @@ group = "com.facebook.react"

val ndkPath by extra(System.getenv("ANDROID_NDK"))
val ndkVersion by extra(System.getenv("ANDROID_NDK_VERSION"))

buildscript {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
dependencies {
classpath("com.android.tools.build:gradle:7.4.1")
classpath("de.undercouch:gradle-download-task:5.0.1")
}
}

val sonatypeUsername = findProperty("SONATYPE_USERNAME")?.toString()
val sonatypePassword = findProperty("SONATYPE_PASSWORD")?.toString()

Expand All @@ -52,14 +45,8 @@ nexusPublishing {

allprojects {
repositories {
maven { url = uri("$rootDir/node_modules/jsc-android/dist") }
maven { url = uri("$rootDir/android") }
google()
mavenCentral {
// We don't want to fetch react-native from Maven Central as there are
// older versions over there.
content { excludeGroup("com.facebook.react") }
}
mavenCentral()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package com.facebook.react

import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.gradle.internal.tasks.factory.dependsOn
import com.facebook.react.internal.PrivateReactExtension
import com.facebook.react.tasks.BuildCodegenCLITask
import com.facebook.react.tasks.GenerateCodegenArtifactsTask
import com.facebook.react.tasks.GenerateCodegenSchemaTask
Expand All @@ -34,8 +35,22 @@ class ReactPlugin : Plugin<Project> {
checkJvmVersion(project)
val extension = project.extensions.create("react", ReactExtension::class.java, project)

// We register a private extension on the rootProject so that project wide configs
// like codegen config can be propagated from app project to libraries.
val rootExtension =
project.rootProject.extensions.findByType(PrivateReactExtension::class.java)
?: project.rootProject.extensions.create(
"privateReact", PrivateReactExtension::class.java, project)

// App Only Configuration
project.pluginManager.withPlugin("com.android.application") {
// We wire the root extension with the values coming from the app (either user populated or
// defaults).
rootExtension.root.set(extension.root)
rootExtension.reactNativeDir.set(extension.reactNativeDir)
rootExtension.codegenDir.set(extension.codegenDir)
rootExtension.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)

project.afterEvaluate {
val reactNativeDir = extension.reactNativeDir.get().asFile
val propertiesFile = File(reactNativeDir, "ReactAndroid/gradle.properties")
Expand All @@ -54,12 +69,12 @@ class ReactPlugin : Plugin<Project> {
project.configureReactTasks(variant = variant, config = extension)
}
}
configureCodegen(project, extension, isLibrary = false)
configureCodegen(project, extension, rootExtension, isLibrary = false)
}

// Library Only Configuration
project.pluginManager.withPlugin("com.android.library") {
configureCodegen(project, extension, isLibrary = true)
configureCodegen(project, extension, rootExtension, isLibrary = true)
}
}

Expand All @@ -82,34 +97,36 @@ class ReactPlugin : Plugin<Project> {
}
}

/**
* A plugin to enable react-native-codegen in Gradle environment. See the Gradle API docs for more
* information: https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html
*/
/** This function sets up `react-native-codegen` in our Gradle plugin. */
@Suppress("UnstableApiUsage")
private fun configureCodegen(project: Project, extension: ReactExtension, isLibrary: Boolean) {
private fun configureCodegen(
project: Project,
localExtension: ReactExtension,
rootExtension: PrivateReactExtension,
isLibrary: Boolean
) {
// First, we set up the output dir for the codegen.
val generatedSrcDir = File(project.buildDir, "generated/source/codegen")

// We specify the default value (convention) for jsRootDir.
// It's the root folder for apps (so ../../ from the Gradle project)
// and the package folder for library (so ../ from the Gradle project)
if (isLibrary) {
extension.jsRootDir.convention(project.layout.projectDirectory.dir("../"))
localExtension.jsRootDir.convention(project.layout.projectDirectory.dir("../"))
} else {
extension.jsRootDir.convention(extension.root)
localExtension.jsRootDir.convention(localExtension.root)
}

val buildCodegenTask =
project.tasks.register("buildCodegenCLI", BuildCodegenCLITask::class.java) {
it.codegenDir.set(extension.codegenDir)
it.codegenDir.set(rootExtension.codegenDir)
val bashWindowsHome = project.findProperty("REACT_WINDOWS_BASH") as String?
it.bashWindowsHome.set(bashWindowsHome)

// Please note that appNeedsCodegen is triggering a read of the package.json at
// configuration time as we need to feed the onlyIf condition of this task.
// Therefore, the appNeedsCodegen needs to be invoked inside this lambda.
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(extension)
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
it.onlyIf { isLibrary || needsCodegenFromPackageJson }
}

Expand All @@ -118,23 +135,24 @@ class ReactPlugin : Plugin<Project> {
project.tasks.register(
"generateCodegenSchemaFromJavaScript", GenerateCodegenSchemaTask::class.java) { it ->
it.dependsOn(buildCodegenTask)
it.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)
it.codegenDir.set(extension.codegenDir)
it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
it.codegenDir.set(rootExtension.codegenDir)
it.generatedSrcDir.set(generatedSrcDir)

// We're reading the package.json at configuration time to properly feed
// the `jsRootDir` @Input property of this task & the onlyIf. Therefore, the
// parsePackageJson should be invoked inside this lambda.
val packageJson = findPackageJsonFile(project, extension)
val packageJson = findPackageJsonFile(project, rootExtension.root)
val parsedPackageJson = packageJson?.let { JsonUtils.fromCodegenJson(it) }

val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir
if (jsSrcsDirInPackageJson != null) {
it.jsRootDir.set(File(packageJson.parentFile, jsSrcsDirInPackageJson))
} else {
it.jsRootDir.set(extension.jsRootDir)
it.jsRootDir.set(localExtension.jsRootDir)
}
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(extension)
val needsCodegenFromPackageJson =
project.needsCodegenFromPackageJson(rootExtension.root)
it.onlyIf { isLibrary || needsCodegenFromPackageJson }
}

Expand All @@ -143,17 +161,18 @@ class ReactPlugin : Plugin<Project> {
project.tasks.register(
"generateCodegenArtifactsFromSchema", GenerateCodegenArtifactsTask::class.java) {
it.dependsOn(generateCodegenSchemaTask)
it.reactNativeDir.set(extension.reactNativeDir)
it.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)
it.reactNativeDir.set(rootExtension.reactNativeDir)
it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
it.generatedSrcDir.set(generatedSrcDir)
it.packageJsonFile.set(findPackageJsonFile(project, extension))
it.codegenJavaPackageName.set(extension.codegenJavaPackageName)
it.libraryName.set(extension.libraryName)
it.packageJsonFile.set(findPackageJsonFile(project, rootExtension.root))
it.codegenJavaPackageName.set(localExtension.codegenJavaPackageName)
it.libraryName.set(localExtension.libraryName)

// Please note that appNeedsCodegen is triggering a read of the package.json at
// configuration time as we need to feed the onlyIf condition of this task.
// Therefore, the appNeedsCodegen needs to be invoked inside this lambda.
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(extension)
val needsCodegenFromPackageJson =
project.needsCodegenFromPackageJson(rootExtension.root)
it.onlyIf { isLibrary || needsCodegenFromPackageJson }
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.internal

import javax.inject.Inject
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.ListProperty

/**
* A private extension we set on the rootProject to make easier to share values at execution time
* between app project and library project.
*
* Specifically, the [codegenDir], [reactNativeDir] and other properties should be provided by apps
* (for setups like a monorepo which are app specific) and libraries should honor those values.
*
* Users are not supposed to access directly this extension from their build.gradle file.
*/
abstract class PrivateReactExtension @Inject constructor(project: Project) {

private val objects = project.objects

val root: DirectoryProperty = objects.directoryProperty()

val reactNativeDir: DirectoryProperty = objects.directoryProperty()

val nodeExecutableAndArgs: ListProperty<String> = objects.listProperty(String::class.java)

val codegenDir: DirectoryProperty = objects.directoryProperty()
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.facebook.react.model.ModelPackageJson
import com.facebook.react.utils.Os.cliPath
import java.io.File
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty

/**
* Computes the entry file for React Native. The Algo follows this order:
Expand Down Expand Up @@ -189,13 +190,13 @@ internal fun projectPathToLibraryName(projectPath: String): String =
* Gradle module (generally the case for library projects) or we fallback to looking into the `root`
* folder of a React Native project (generally the case for app projects).
*/
internal fun findPackageJsonFile(project: Project, extension: ReactExtension): File? {
internal fun findPackageJsonFile(project: Project, rootProperty: DirectoryProperty): File? {
val inParent = project.file("../package.json")
if (inParent.exists()) {
return inParent
}

val fromExtension = extension.root.file("package.json").orNull?.asFile
val fromExtension = rootProperty.file("package.json").orNull?.asFile
if (fromExtension?.exists() == true) {
return fromExtension
}
Expand All @@ -207,12 +208,15 @@ internal fun findPackageJsonFile(project: Project, extension: ReactExtension): F
* Function to look for the `package.json` and parse it. It returns a [ModelPackageJson] if found or
* null others.
*
* Please note that this function access the [ReactExtension] field properties and calls .get() on
* them, so calling this during apply() of the ReactPlugin is not recommended. It should be invoked
* inside lazy lambdas or at execution time.
* Please note that this function access the [DirectoryProperty] parameter and calls .get() on them,
* so calling this during apply() of the ReactPlugin is not recommended. It should be invoked inside
* lazy lambdas or at execution time.
*/
internal fun readPackageJsonFile(project: Project, extension: ReactExtension): ModelPackageJson? {
val packageJson = findPackageJsonFile(project, extension)
internal fun readPackageJsonFile(
project: Project,
rootProperty: DirectoryProperty
): ModelPackageJson? {
val packageJson = findPackageJsonFile(project, rootProperty)
return packageJson?.let { JsonUtils.fromCodegenJson(it) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

package com.facebook.react.utils

import com.facebook.react.ReactExtension
import com.facebook.react.model.ModelPackageJson
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty

internal object ProjectUtils {
internal val Project.isNewArchEnabled: Boolean
Expand All @@ -35,8 +35,8 @@ internal object ProjectUtils {
HERMES_FALLBACK
}

internal fun Project.needsCodegenFromPackageJson(extension: ReactExtension): Boolean {
val parsedPackageJson = readPackageJsonFile(this, extension)
internal fun Project.needsCodegenFromPackageJson(rootProperty: DirectoryProperty): Boolean {
val parsedPackageJson = readPackageJsonFile(this, rootProperty)
return needsCodegenFromPackageJson(parsedPackageJson)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ class PathUtilsTest {
project.plugins.apply("com.facebook.react")
val extension = project.extensions.getByType(ReactExtension::class.java)

assertEquals(project.file("../package.json"), findPackageJsonFile(project, extension))
assertEquals(project.file("../package.json"), findPackageJsonFile(project, extension.root))
}

@Test
Expand All @@ -245,7 +245,7 @@ class PathUtilsTest {
val extension =
project.extensions.getByType(ReactExtension::class.java).apply { root.set(moduleFolder) }

assertEquals(localFile, findPackageJsonFile(project, extension))
assertEquals(localFile, findPackageJsonFile(project, extension.root))
}

@Test
Expand All @@ -257,7 +257,7 @@ class PathUtilsTest {
val extension =
project.extensions.getByType(ReactExtension::class.java).apply { root.set(moduleFolder) }

val actual = readPackageJsonFile(project, extension)
val actual = readPackageJsonFile(project, extension.root)

assertNull(actual)
}
Expand All @@ -272,7 +272,7 @@ class PathUtilsTest {
val extension =
project.extensions.getByType(ReactExtension::class.java).apply { root.set(moduleFolder) }

val actual = readPackageJsonFile(project, extension)
val actual = readPackageJsonFile(project, extension.root)

assertNotNull(actual)
assertNull(actual!!.codegenConfig)
Expand All @@ -298,7 +298,7 @@ class PathUtilsTest {
val extension =
project.extensions.getByType(ReactExtension::class.java).apply { root.set(moduleFolder) }

val actual = readPackageJsonFile(project, extension)
val actual = readPackageJsonFile(project, extension.root)

assertNotNull(actual)
assertNotNull(actual!!.codegenConfig)
Expand Down
Loading