升级 Android targetSDK 至 35 并使用 Gradle 8.0+ 后,遇到了第三方库 namespace 配置问题。
错误信息 
1 
2 
3 
4 
Execution failed for  task ':react-native-inappbrowser:processDebugManifest' . 
 >  A failure occurred while  executing com.android.build.gradle.tasks.ProcessLibraryManifest$ProcessLibWorkAction 
>  Setting the namespace via the package attribute in  the source  AndroidManifest.xml is no longer supported.
  Recommendation: remove package = "com.proyecto26.inappbrowser"  from the source  AndroidManifest.xml. 
或者类似错误:
1 
2 
3 
4 
5 
Namespace not specified. Please specify a namespace in  the module's build.gradle file like so:
 
 android {
     namespace ' com.example.namespace'
 }  
原因分析 
Android Gradle Plugin 8.0+ 不再支持在 AndroidManifest.xml 中通过 package 属性设置 namespace,要求在 build.gradle 中显式声明。升级 targetSDK 至 35 需要使用 Gradle 8.0+,但很多第三方库(如 react-native-inappbrowser、appcenter-analytics 等)尚未更新配置,导致构建失败。
解决方案 
在项目根目录的 android/build.gradle 文件中添加以下代码:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
allprojects  { 
    repositories  { 
         google () 
         mavenCentral () 
         
         // 如果使用 Detox 测试框架,添加此配置 
         maven  { 
             url ( "$rootDir/../node_modules/detox/Detox-android" ) 
         } 
     } 
     
     subprojects  { 
         afterEvaluate  {  project  -> 
             if  ( project . hasProperty ( 'android' ))  { 
                 project . android  { 
                     // 自动设置 namespace 
                     if  ( namespace  ==  null  ||  namespace . isEmpty ())  { 
                         def  defaultNamespace  =  project . group . toString (). replace ( '.' ,  '_' ) 
                         namespace  =  defaultNamespace 
                     } 
 
                     // 启用 buildConfig 
                     buildFeatures  { 
                         buildConfig  =  true 
                     } 
                 } 
 
                 // 自动修复 namespace 和清理 AndroidManifest.xml 
                 project . tasks . register ( "fixManifestsAndNamespace" )  { 
                     doLast  { 
                         // 1. 从 AndroidManifest.xml 提取 package 并添加到 build.gradle 
                         def  buildGradleFile  =  file ( "${project.projectDir}/build.gradle" ) 
                         if  ( buildGradleFile . exists ())  { 
                             def  buildGradleContent  =  buildGradleFile . getText ( 'UTF-8' ) 
                             def  manifestFile  =  file ( "${project.projectDir}/src/main/AndroidManifest.xml" ) 
                             if  ( manifestFile . exists ())  { 
                                 def  manifestContent  =  manifestFile . getText ( 'UTF-8' ) 
                                 def  packageName  =  manifestContent . find ( /package="([^"]+)"/ )  {  match ,  p  ->  p  } 
                                 if  ( packageName  &&  ! buildGradleContent . contains ( "namespace" ))  { 
                                     println  "Setting namespace in ${buildGradleFile}" 
                                     buildGradleContent  =  buildGradleContent . replaceFirst ( 
                                         /android\s*\{/ ,  "android {\n    namespace '${packageName}'" 
                                     ) 
                                     buildGradleFile . write ( buildGradleContent ,  'UTF-8' ) 
                                 } 
                             } 
                         } 
 
                         // 2. 移除 AndroidManifest.xml 中的 package 属性 
                         def  manifests  =  fileTree ( dir:  project . projectDir ,  includes:  [ '**/AndroidManifest.xml' ]) 
                         manifests . each  {  File  manifestFile  -> 
                             def  manifestContent  =  manifestFile . getText ( 'UTF-8' ) 
                             if  ( manifestContent . contains ( 'package=' ))  { 
                                 println  "Removing package attribute from ${manifestFile}" 
                                 manifestContent  =  manifestContent . replaceAll ( /package="[^"]*"/ ,  '' ) 
                                 manifestFile . write ( manifestContent ,  'UTF-8' ) 
                             } 
                         } 
                     } 
                 } 
 
                 // 在构建前自动执行修复 
                 project . tasks . matching  {  it . name . startsWith ( "preBuild" )  }. all  { 
                     dependsOn  project . tasks . named ( "fixManifestsAndNamespace" ) 
                 } 
             } 
         } 
     } 
 } 
说明 
工作原理 
此方案包含三个层次的处理:
  自动设置 namespace :如果子项目未配置 namespace,自动使用 project.group 并将点号替换为下划线作为 namespace启用 buildConfig :自动为所有子项目启用 buildConfig 特性自动迁移配置 :
    
      从 AndroidManifest.xml 中提取 package 属性 
      将其写入对应的 build.gradle 作为 namespace 
      移除 AndroidManifest.xml 中的 package 属性 
     
   
这个 task 在每次构建前(preBuild)自动执行,确保所有第三方库都符合 Gradle 8.0+ 的要求。
适用场景 
  React Native 项目升级 targetSDK 35 
  Flutter 项目升级 targetSDK 35 
  使用 Detox 测试框架的项目 
  原生 Android 项目使用旧版第三方库 
  任何遇到 “namespace not specified” 或 “package attribute not supported” 错误的场景 
 
注意事项 
  此方案会自动修改 第三方库的 build.gradle 和 AndroidManifest.xml 文件 
  修改仅在 node_modules 中生效,不影响源码仓库 
  建议在 CI/CD 中首次构建后检查修改是否正确 
  如果某些库已经声明了 namespace,不会被覆盖 
 
验证 
执行以下命令重新构建项目:
1 
2 
3 
cd  android
./gradlew clean
 ./gradlew assembleDebug 
或在 React Native 项目中:
1 
npx react-native run-android 
构建过程中会看到类似输出:
1 
2 
Setting namespace in  /path/to/project/android/react-native-inappbrowser/build.gradle
 Removing package attribute from /path/to/project/android/react-native-inappbrowser/src/main/AndroidManifest.xml 
与简化方案对比 
如果只需要为缺少 namespace 的库自动设置默认值,可以使用简化版:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
subprojects  { 
    afterEvaluate  {  project  -> 
         if  ( project . hasProperty ( 'android' ))  { 
             project . android  { 
                 if  ( namespace  ==  null  ||  namespace . isEmpty ())  { 
                     namespace  project . group . toString (). replace ( '.' ,  '_' ) 
                 } 
             } 
         } 
     } 
 } 
简化方案不会修改任何文件,仅在内存中设置 namespace,但可能无法解决所有第三方库的问题。
参考