diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt index f7bd68eeb2e5..4af3f14f34ce 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt @@ -113,6 +113,30 @@ class ReactPlugin : Plugin { configureCodegen(project, extension, rootExtension, isLibrary = false) configureResources(project, extension) configureBuildTypesForApp(project) + + // Apply the namespace fallback to every Android library in the build, including third-party + // libraries that don't apply the `com.facebook.react` plugin and still rely on the manifest + // `package` attribute (which AGP 9 no longer accepts as a namespace). The per-library hook + // below only covers libraries that apply our plugin, so we additionally sweep all library + // subprojects from the app. We do this once, from the application project, because re-running + // a rootProject-wide traversal from every library breaks on AGP 9, which errors when + // `finalizeDsl` is registered after a project's DSL has been finalized. + // See https://github.com/facebook/react-native/pull/57038. + // + // We skip projects that have already been evaluated: AGP finalizes a project's DSL during/ + // after its evaluation, so registering a `finalizeDsl` callback on an already-evaluated + // project is "too late" and fails on AGP 9. In a regular app build the app is evaluated + // before its libraries (see ReactRootProjectPlugin's `evaluationDependsOn(":app")`), so every + // library is still pending here. In composite/monorepo builds (e.g. rn-tester, where + // ReactAndroid is a sibling) some library projects are already evaluated by this point; those + // already define their own namespace, so skipping them is safe. + project.rootProject.allprojects { subproject -> + subproject.pluginManager.withPlugin("com.android.library") { + if (!subproject.state.executed) { + configureNamespaceForLibraries(subproject) + } + } + } } // Library Only Configuration diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt index 8d2b31f13390..36a52185a6d0 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt @@ -106,6 +106,15 @@ internal object AgpConfiguratorUtils { } fun configureNamespaceForLibraries(project: Project) { + // This helper can be reached both from a library's own application of the React plugin and + // from the app-level sweep in ReactPlugin (which also covers libraries that don't apply + // `com.facebook.react`). A project's `finalizeDsl` callback must be registered before AGP + // finalizes its DSL — registering it twice (or after finalization) is a hard error on AGP 9+ — + // so we guard to register the namespace fallback at most once per project. + if (project.extensions.extraProperties.has(NAMESPACE_CONFIGURED_PROPERTY)) { + return + } + project.extensions.extraProperties.set(NAMESPACE_CONFIGURED_PROPERTY, true) project.extensions.getByType(LibraryAndroidComponentsExtension::class.java).finalizeDsl { ext -> if (ext.namespace == null) { val manifestFile = @@ -122,6 +131,8 @@ internal object AgpConfiguratorUtils { } } +private const val NAMESPACE_CONFIGURED_PROPERTY = "com.facebook.react.internal.namespaceConfigured" + const val DEFAULT_DEV_SERVER_PORT = "8081" fun getPackageNameFromManifest(manifest: File): String? {