Skip to content

Commit 13ae111

Browse files
gabrieldonadelfacebook-github-bot
authored andcommitted
Ensure namespace is specified for all the 3rd party libraries (#41085)
Summary: As stated here react-native-community/discussions-and-proposals#671 React Native 0.73 will depend on Android Gradle Plugin (AGP) 8.x which requires all libraries to specify a namespace in their build.gradle file, even though this issue was raised many months ago, lots of libraries have not been updated and don't specify a `namespace` inside their build.gradle files ## Changelog: [ANDROID] [CHANGED] - Ensure namespace is specified for all the 3rd party libraries Pull Request resolved: #41085 Test Plan: Run RNGP tests and test building rn-tester after doing the following procedure 1. Remove `namespace "com.facebook.react"` from react-native/packages/react-native/ReactAndroid/build.gradle 2. Add `package="com.facebook.react"` to react-native/packages/react-native/ReactAndroid/src/main/AndroidManifest.xml 3. Build rn-tester Also tested this using [BareExpo](https://github.com/expo/expo/tree/main/apps/bare-expo) with AGP 8.1.1 and all libraries that were missing the `namespace` compiled correctly Reviewed By: cipolleschi Differential Revision: D50556667 Pulled By: cortinico fbshipit-source-id: 3d75ec0a8b82427ff0ede89aa7bc58b28b288945
1 parent 8809392 commit 13ae111

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.facebook.react.tasks.GenerateCodegenSchemaTask
1515
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForApp
1616
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForLibraries
1717
import com.facebook.react.utils.AgpConfiguratorUtils.configureDevPorts
18+
import com.facebook.react.utils.AgpConfiguratorUtils.configureNamespaceForLibraries
1819
import com.facebook.react.utils.BackwardCompatUtils.configureBackwardCompatibilityReactMap
1920
import com.facebook.react.utils.DependencyUtils.configureDependencies
2021
import com.facebook.react.utils.DependencyUtils.configureRepositories
@@ -82,6 +83,7 @@ class ReactPlugin : Plugin<Project> {
8283

8384
// Library Only Configuration
8485
configureBuildConfigFieldsForLibraries(project)
86+
configureNamespaceForLibraries(project)
8587
project.pluginManager.withPlugin("com.android.library") {
8688
configureCodegen(project, extension, rootExtension, isLibrary = true)
8789
}

packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88
package com.facebook.react.utils
99

1010
import com.android.build.api.variant.AndroidComponentsExtension
11+
import com.android.build.gradle.LibraryExtension
1112
import com.facebook.react.ReactExtension
1213
import com.facebook.react.utils.ProjectUtils.isHermesEnabled
1314
import com.facebook.react.utils.ProjectUtils.isNewArchEnabled
15+
import java.io.File
16+
import javax.xml.parsers.DocumentBuilder
17+
import javax.xml.parsers.DocumentBuilderFactory
1418
import org.gradle.api.Action
1519
import org.gradle.api.Project
1620
import org.gradle.api.plugins.AppliedPlugin
21+
import org.w3c.dom.Element
1722

1823
@Suppress("UnstableApiUsage")
1924
internal object AgpConfiguratorUtils {
@@ -63,6 +68,43 @@ internal object AgpConfiguratorUtils {
6368
project.pluginManager.withPlugin("com.android.application", action)
6469
project.pluginManager.withPlugin("com.android.library", action)
6570
}
71+
72+
fun configureNamespaceForLibraries(appProject: Project) {
73+
appProject.rootProject.allprojects { subproject ->
74+
subproject.pluginManager.withPlugin("com.android.library") {
75+
subproject.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext ->
76+
if (ext.namespace == null) {
77+
val android = subproject.extensions.getByType(LibraryExtension::class.java)
78+
val manifestFile = android.sourceSets.getByName("main").manifest.srcFile
79+
80+
manifestFile
81+
.takeIf { it.exists() }
82+
?.let { file ->
83+
getPackageNameFromManifest(file)?.let { packageName ->
84+
ext.namespace = packageName
85+
}
86+
}
87+
}
88+
}
89+
}
90+
}
91+
}
6692
}
6793

6894
const val DEFAULT_DEV_SERVER_PORT = "8081"
95+
96+
fun getPackageNameFromManifest(manifest: File): String? {
97+
val factory: DocumentBuilderFactory = DocumentBuilderFactory.newInstance()
98+
val builder: DocumentBuilder = factory.newDocumentBuilder()
99+
100+
try {
101+
val xmlDocument = builder.parse(manifest)
102+
103+
val manifestElement = xmlDocument.getElementsByTagName("manifest").item(0) as? Element
104+
val packageName = manifestElement?.getAttribute("package")
105+
106+
return if (packageName.isNullOrEmpty()) null else packageName
107+
} catch (e: Exception) {
108+
return null
109+
}
110+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.utils
9+
10+
import java.io.File
11+
import org.junit.Assert.*
12+
import org.junit.Rule
13+
import org.junit.Test
14+
import org.junit.rules.TemporaryFolder
15+
16+
class AgpConfiguratorUtilsTest {
17+
18+
@get:Rule val tempFolder = TemporaryFolder()
19+
20+
@Test
21+
fun getPackageNameFromManifest_withEmptyFile_returnsNull() {
22+
val mainFolder = tempFolder.newFolder("awesome-module/src/main/")
23+
val manifest = File(mainFolder, "AndroidManifest.xml").apply { writeText("") }
24+
25+
val actual = getPackageNameFromManifest(manifest)
26+
assertNull(actual)
27+
}
28+
29+
@Test
30+
fun getPackageNameFromManifest_withMissingPackage_returnsNull() {
31+
val mainFolder = tempFolder.newFolder("awesome-module/src/main/")
32+
val manifest =
33+
File(mainFolder, "AndroidManifest.xml").apply {
34+
writeText(
35+
// language=xml
36+
"""
37+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
38+
</manifest>
39+
"""
40+
.trimIndent())
41+
}
42+
43+
val actual = getPackageNameFromManifest(manifest)
44+
assertNull(actual)
45+
}
46+
47+
@Test
48+
fun getPackageNameFromManifest_withPackage_returnsPackage() {
49+
val mainFolder = tempFolder.newFolder("awesome-module/src/main/")
50+
val manifest =
51+
File(mainFolder, "AndroidManifest.xml").apply {
52+
writeText(
53+
// language=xml
54+
"""
55+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.facebook.react" >
56+
</manifest>
57+
"""
58+
.trimIndent())
59+
}
60+
61+
val actual = getPackageNameFromManifest(manifest)
62+
assertNotNull(actual)
63+
assertEquals("com.facebook.react", actual)
64+
}
65+
}

0 commit comments

Comments
 (0)