在使用flutterSDK 3.24之后发现新建项目,项目默认都是基于AGP8了,由于 AGP 开始强制要求 namespace 配置,不仅仅是主工程,也包括第三方库都强制要求 namespace 。但是我们在引入第三方库的时候会发现部分库没能及时的去做相关配置,这也就导致了我们会出现标题错误:
出现这个问题,我们可能会通过去找到本地缓存的第三方库代码去修改它的build.gradle和AndroidManifest.xml来解决缺失 namespace 的报错问题,但是显然这种方式不太友好,毕竟正常项目可能会引用很多库,这个时候一个一个去修改太麻烦了。因此我们需要一种可以批量处理的方式,在编译的时候去做处理。
话不多说直接上代码吧,但还是建议连同下方补充的两项一起看完:
java
allprojects {
repositories {
google()
mavenCentral()
}
}
subprojects {
afterEvaluate { project ->
if (project.plugins.hasPlugin('com.android.library') || project.plugins.hasPlugin('com.android.application')) {
println "project: ${project.name} Namespace get: ${project.android.namespace}"
def packageName = project.android.namespace ?: project.android.defaultConfig.applicationId ?: project.android.sourceSets.main.manifest.srcFile.text.find(/package="([^"]*)"/) ?: project.group
project.android.namespace = packageName
println "Namespace set to: ${packageName} for project: ${project.name}"
}
}
}
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
通过在根目录下的build.gradle文件中添加以下代码就可以在编译的时候批量处理:
java
subprojects {
afterEvaluate { project ->
if (project.plugins.hasPlugin('com.android.library') || project.plugins.hasPlugin('com.android.application')) {
println "project: ${project.name} Namespace get: ${project.android.namespace}"
def packageName = project.android.namespace ?: project.android.defaultConfig.applicationId ?: project.android.sourceSets.main.manifest.srcFile.text.find(/package="([^"]*)"/) ?: project.group
project.android.namespace = packageName
println "Namespace set to: ${packageName} for project: ${project.name}"
}
}
}
我让GPT写了一下代码解释,有兴趣的可以看一下:
以下是对这段代码的分析:
一、整体功能
这段 Groovy 代码主要是在 Gradle 项目中针对 Android 项目(包括 Android 库项目和应用项目)进行处理。具体功能包括获取项目的命名空间(package name),并在必要时进行设置。
二、代码结构及解释
1、afterEvaluate
闭包:
在 Gradle 项目评估完成后执行的代码块。这意味着在项目的配置阶段结束后,这段代码才会被执行。
2、条件判断:
if (project.plugins.hasPlugin('com.android.library') ||project.plugins.hasPlugin('com.android.application'))
:检查项目是否应用了 Android 库插件或 Android 应用插件。只有满足这个条件的项目才会执行后续的代码。
3、获取和设置命名空间:
println "project: ${project.name} Namespace get: ${project.android.namespace}"
:打印当前项目的名称和已有的命名空间。
def packageName = project.android.namespace?: project.android.defaultConfig.applicationId?: project.android.sourceSets.main.manifest.srcFile.text.find(/package="([^"]*)"/)?: project.group
:尝试从多个来源获取命名空间。如果项目已经设置了android.namespace
,则使用该值;如果没有,尝试使用android.defaultConfig.applicationId;
如果还没有,从 AndroidManifest.xml
文件中提取package属性的值;如果仍然没有找到,最后使用项目的group作为命名空间。
project.android.namespace = packageName
:设置项目的命名空间为获取到的packageName
。
println "Namespace set to: ${packageName} for project: ${project.name}"
:打印设置后的命名空间和项目名称。
最后我们再运行一下看看吧!

OK,成功运行!
补充一:如果出现如下截图错误的话
就改成下面代码,用来清除AndroidManifest.xml
中的package
,
java
subprojects {
afterEvaluate { project ->
if (project.plugins.hasPlugin('com.android.library') || project.plugins.hasPlugin('com.android.application')) {
println "project: ${project.name} Namespace get: ${project.android.namespace}"
def packageName = project.android.namespace ?: project.android.defaultConfig.applicationId ?: project.android.sourceSets.main.manifest.srcFile.text.find(/package="([^"]*)"/) ?: project.group
project.android.namespace = packageName
println "Namespace set to: ${packageName} for project: ${project.name}"
def manifestFile = project.android.sourceSets.main.manifest.srcFile
if (manifestFile.exists()) {
def manifestText = manifestFile.text
if (manifestText.contains('package=')) {
manifestText = manifestText.replaceAll(/package="[^"]*"/, "")
manifestFile.text = manifestText
println "Package attribute removed in AndroidManifest.xml for project: ${project.name}"
} else {
println "No package attribute found in AndroidManifest.xml for project: ${project.name}"
}
} else {
println "AndroidManifest.xml not found for project: ${project.name}"
}
}
}
}
注意添加完之后,第一次运行可能会报错,这个具体原因不清楚,不过不用管,接着再运行一次就可以了

补充二:如果出现如下截图错误的话可以通过配置gradle.properties
文件添加这两行内容就可以了正常运行了。
android.nonTransitiveRClass=false
android.nonFinalResIds=false
