Skip to content

feat: introduce com.facebook.react.library as separate library plugin - #57912

Draft
hurali97 wants to merge 4 commits into
react:mainfrom
hurali97:feat/separate-library-plugin
Draft

feat: introduce com.facebook.react.library as separate library plugin#57912
hurali97 wants to merge 4 commits into
react:mainfrom
hurali97:feat/separate-library-plugin

Conversation

@hurali97

@hurali97 hurali97 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary:

This PR extracts the library facing changes from RNGP to a separate RN Library plugin. We now have com.facebook.react - meant to be applied by the applications and com.facebook.react.library meant to be applied by the libraries.

The foundation works in a compatible way. Which means that the existing libraries which applies the RNGP, will now get a deprecation notice to switch to the RN library plugin while still allowing existing libraries to work for the defined future releases.

Maintaining this compatibility requires us to introduce a new shared (react-native-gradle-plugin-shared) plugin which is only shared between RNGP and RN Library plugin. We can't put this shared code as it requires AGP dependency, in the existing shared plugin as it is also consumed by the settings plugin. So we have to take this tradeoff for having an extra plugin until we fully deprecate using RNGP in libraries.

The consumption of the RN library plugin is as simple as the following change in awesome-rn-library/android/build.gradle:

diff --git a/android/build.gradle b/android/build.gradle
index c3ef3a0a..78ae00f7 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -23,6 +23,7 @@ buildscript {
         classpath('com.android.tools.build:gradle:8.2.1')
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', rnsDefaultKotlinVersion)}"
         classpath "com.diffplug.spotless:spotless-plugin-gradle:6.25.0"
+        classpath("com.facebook.react:react-native-library-plugin")
     }
 }

@@ -83,7 +84,7 @@ def resolveReactNativeDirectory() {
 if (isRunningInContextOfScreensRepo()) {
     apply from: 'spotless.gradle'
 } else {
-    apply plugin: "com.facebook.react"
+    apply plugin: "com.facebook.react.library"
 }
 apply plugin: 'com.android.library'

Since each third party library project is linked as a sub project to the application and in there at awesome-app/android/settings.gradle we define includeBuild(...gradle-plugin) - the RN library plugin gets resolved as well as part of the dependency resolution.

Changelog:

[ANDROID] [ADDED] - Introduce com.facebook.react.library as a separate and preferred library plugin

Test Plan:

  • Verified locally on an App with react-native-screens, react-native-worklets, react-native-reaniamted and react-native-safe-area-context
Case 1, we see deprecation notice when all these 4 libraries use RNGP with backward compat rngp
Case 2, we see deprecation notice when 3 libraries use RNGP while RN screen uses new library plugin new

  • The kotlin-android compat is also verified on the above case
Case 1, builtin kotlin not enabled, on AGP v8 no-builtin
Case 2, builtin kotlin enabled, on AGP v9

TBA

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 12, 2026
@hurali97

Copy link
Copy Markdown
Contributor Author

In this PR, we only use RN library plugin in react-native-popup-menu-android and ReactAndroid, hermes-engine and react-native-fantom uses RNGP, to indicate backward compatibility.

Also, there are internal Tasks currently a part of RNGP, which are used by ReactAndroid, hermes-engine and react-native-fantom:

  • Since the consumers are essentially a library, we can move these tasks to the RN library plugin.
  • However, since they are internal, we can create an internal plugin which exposes these APIs to internal libraries.

I believe all the internal libraries should use the library plugin and not worry about showcasing backward compat by using RNGP. Also, we may move with the first option, since it seems rather simpler but offers less abstraction as it will contain internal tasks as part of a public package.

@hurali97

Copy link
Copy Markdown
Contributor Author

If we wish to extract the RN library plugin to a separate repo, then we have a few options. The RN Library plugin depends on shared and RNGP-shared plugin.

Usage will look something like below in awesome-rn-library/android/build.gradle:

diff --git a/android/build.gradle b/android/build.gradle
index fee43d64..3b3f5ade 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -23,7 +23,7 @@ buildscript {
         classpath('com.android.tools.build:gradle:8.2.1')
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', rnsDefaultKotlinVersion)}"
         classpath "com.diffplug.spotless:spotless-plugin-gradle:6.25.0"
+        classpath("com.facebook.react:react-native-library-plugin:0.0.1") // or RN version if we want to tie it to a specific RN version
     }
 }

Approaches:

  • Publish the required plugins to maven central
  • Hybrid approach, leverage composite build to substitute required plugins

The first approach would require us to publish the required plugins to maven and then they will be auto resolved by gradle during dependency resolution. However, there is higher chance of shared and rngp-shared being supplied via the composite includeBuild(..gradle-plugin) unless we set useGlobalDependencySubstitutionRules=false .

The second approach is where we leverage the current shape of resolving gradle-plugins from RN using composite builds. The awesome-rn-library applies the RNGP and it gets defined in awesome-rn-app and gets resolved via composite builds.

Now, we extract the RN Library plugin to a separate repo but it still depends on shared and rngp-shared modules. We do a custom wiring in that repo to fulfill the compile time dependency and use the composite builds to provide these modules. Here comes the interesting part. We publish this RN library plugin to maven but not the other ones and during the dependency resolution phase, the gradle substitute the shared and rngp-shared from the composite build, however since its a substitution, there needs to be an explicit check and alignment on the version of RN between composite build and RN library from Maven.

There is also a third path, where we dont extract the RN library plugin to separate repo but still publish it to maven central. However, since now it's a part of gradle-plugins, we will need to restrict the composite build from substituting RN library plugin, the following change will be required from awesome-rn-app/android/build,gradle OR we can extract this in settings plugin:

includeBuild("../node_modules/@react-native/gradle-plugin") {
    dependencySubstitution {
        substitute module(
            "com.facebook.react:react-native-gradle-plugin"
        ) using project(":react-native-gradle-plugin")

        substitute module(
            "com.facebook.react:react-native-gradle-plugin-shared"
        ) using project(":react-native-gradle-plugin-shared")

        substitute module(
            "com.facebook.react:shared"
        ) using project(":shared")
    }
}

However, this may create some complications and extra steps for the end users. Depending upon how and where we decide to constraint it, in settings.gradle so at consumer's end OR in settings plugin, at RN end.

@cortinico cortinico left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The biggest problem I see here is that you'll be versioning this library plugin with the same version of react-native.

That is a problem as a library will now have to depend on a given version of @react-native/gradle-plugin right?

Instead I believe this plugin should live in a separate repo and be released on-demand whenever needed. If we do so, we also need to make sure the Kotlin classes are not clashing with the same Kotlin classes inside RNGP (i.e. we can't really share code between the two).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants