Gradle报错Plugin with id ‘maven‘ not found:根因解析与迁移方案 📅 发布时间:2026/9/11 3:28:05 👁 浏览次数: 这个报错我见得太多了尤其是这两年把老项目从旧版 Gradle 往上抬的时候几乎隔三差五就会有人把这段异常日志甩到群里。org.gradle.api.plugins.UnknownPluginException: Plugin with id maven not found.翻译过来就是Gradle 在你当前的项目环境里找不到一个叫maven的插件。很多人第一反应是先检查仓库地址、清缓存结果折腾半天发现根本没用。因为这不是下载或者网络问题而是 Gradle 从某个版本开始对maven这个老插件动了刀。本文我会从插件演进原理讲清楚为什么报这个错再给出迁移方案、临时规避办法以及配套的仓库镜像、离线包等环境问题的处理思路基本覆盖你在搜这个问题时可能踩到的所有坑。1. 报错根因解析maven 插件为什么不灵了1.1 先认清这个报错的完整面完整的报错通常长这样出现在编译的配置阶段* What went wrong: A problem occurred evaluating project :app. Plugin with id maven not found.有些情况还会在前面多一行Could not resolve plugin或者提示这类插件来自某个已失效的 DSL。不管什么形态本质都一样你写的apply plugin: maven或者id maven在当前 Gradle 版本里已经不存在了Gradle 按名字去插件仓库里找找不到就直接抛出UnknownPluginException。这个报错高发于三种场景你从 Git 仓库拉了一个老项目本地用的却是新版 Gradle。原有项目在升级 Gradle 或 Android Gradle PluginAGP版本。你照着几年前的博客教程配置uploadArchives发布组件里面用了apply plugin: maven。很多时候大家第一反应是 插件地址配错了镜像没配但实际上问题出在 Gradle 版本的兼容性上。搞清楚了这一点后面所有方案才有意义。1.2 Gradle 插件的前世今生要理解为什么maven会消失得先聊一段 Gradle 插件的历史。早期 Gradle 内置了一套 Maven 插件提供两个核心能力把项目构件上传到本地或远程 Maven 仓库。生成 Maven 项目描述文件POM让其他构建系统能够识别和组织依赖元数据。那时候 Android 开发者要做模块发布最通用的写法就是apply plugin: maven uploadArchives { repositories.mavenDeployer { repository(url: http://your-repo/repository/android/) { authentication(userName: admin, password: admin) } pom.version 1.0.0 pom.artifactId your-library pom.groupId com.example } }这段配置伴生了很长一段时间的 Android 组件发布需求。但 Gradle 团队在发展到 maven-publish 插件后老maven插件逐渐被标记为过时并在 Gradle 7.0 正式移除。所以你现在用 Gradle 7.x 或 8.x 去执行老项目的构建脚本必然触发UnknownPluginException。从功能上看maven和maven-publish是一对旧新交替的关系老插件是命令式的uploadArchives任务新插件是基于publishing扩展的声明式配置模型。后面我会给出具体替换代码。1.3 为什么总是莫名其妙中招很多读者会问我又没有主动用maven插件为什么报错常见的情况是项目里某个子模块、某个被apply from引用的脚本文件或者某些第三方 SDK 自带的 Gradle 脚本里仍然保留了apply plugin: maven的写法。你检查主模块build.gradle时看不出问题但 Gradle 在配置阶段会遍历所有项目对象和脚本文件只要有一个地方引用到不存在的插件类整个构建就会失败。另外Flutter 项目也会遇到类似现象。当你用旧版 Flutter 项目模板去适配新的 Android Gradle Plugin 时you are applying flutters main gradle plugin imperatively using the apply这串提示经常伴随出现。虽然报错措辞不同但背后的逻辑一致老脚本调用了新 Gradle 已经移除或改名的 API。注意排查这类问题时不要把眼光只放在当前能看到的 build.gradle上凡是项目里所有build.gradle、settings.gradle、gradle脚本目录下的文件以及各种.gradle混淆脚本都必须统一搜索一遍。2. 快速定位到底是谁在引用 maven 插件2.1 三步定位法既然根因是某处调用了maven插件那么解决问题的第一步是快速定位到案发现场。我的建议是按下面三步走第一步全局搜索字符串。在项目根目录执行grep -r apply plugin: maven --include*.gradle . grep -r id maven --include*.gradle .Windows 用户如果用的 Android Studio直接Ctrl Shift F全局搜索plugin: maven或者id maven记得把搜索范围设置为Directory不要只在当前文件里找。搜索结果可能分布在根目录build.gradle每个子模块的build.gradlegradle/目录下的脚本文件buildSrc里的自定义插件逻辑第二步检查apply from引用的外部脚本。有些项目习惯把通用发布逻辑放到独立脚本里比如gradle/publish.gradle然后在模块里用apply from: rootProject.file(gradle/publish.gradle)如果这个外部脚本里写了apply plugin: maven不管你自己主脚本写得再干净一样会触发报错。这一步容易被忽略建议把项目里所有apply from指向的文件都翻一遍。第三步确认是否是第三方依赖里的脚本在捣鬼。如果全局搜索都搜不到那就可能是某个 SDK 或插件在内部引用了maven插件。这个情况排查难度稍大但也别急着绝望。一般发生在老版本的第三方发布插件比如某些私有化组件库的 Gradle 插件上。你可以在报错堆栈里找到它是从哪个依赖解析出来的再决定是升级插件版本、临时修改脚本还是干脆换用其他方案。2.2 报错堆栈里透露的关键信息UnknownPluginException完整堆栈一般会明确告诉你是在评估哪个项目或哪个脚本时出现的比如A problem occurred evaluating project :library.看到:library基本锁定问题出在library模块的build.gradle里。有时候还会明确到行号直接跳过去改就行。如果堆栈显示evaluating root project那问题就在根构建脚本或者全局配置里头。结合全局搜索的结果基本能在十分钟内定位到源头。2.3.kts脚本的情况有些新项目用的是 Kotlin DSLbuild.gradle.kts里如果写了plugins { id(maven) }或者apply(plugin maven)报错文案会有些出入但本质相同。解决方案也是把maven改成maven-publish。3. 解决方案一从 maven 迁移到 maven-publish推荐3.1 插件声明怎么改确定问题来源后最干净的修复方式是把老插件改成新插件。改动很简单Groovy DSL 的 build.gradle// 旧写法 apply plugin: maven // 新写法 apply plugin: maven-publishKotlin DSL 的 build.gradle.kts// 旧写法 apply(plugin maven) // 新写法 apply(plugin maven-publish)这一步做完UnknownPluginException就会消失因为maven-publish从 Gradle 7.0 开始是内置的吗严格说maven-publish同样属于 Gradle 核心插件不过它有自己的插件 ID并且一直保留在 Gradle 分发版里所有版本都能直接用。3.2 同步替换 uploadArchives 配置只改插件声明还不够。如果项目里还保留uploadArchives { repositories.mavenDeployer { ... } }这段老配置新插件maven-publish下是没有uploadArchives任务和mavenDeployer扩展的。构建时会报另一个错比如找不到uploadArchives或者mavenDeployer。正确做法是把整套发布配置迁移到publishing扩展apply plugin: maven-publish publishing { publications { mavenJava(MavenPublication) { groupId com.example artifactId your-library version 1.0.0 // 发布 Android Library 时 artifact($buildDir/outputs/aar/your-library-release.aar) // 或发布 Java Library 时 from components.java } } repositories { maven { url uri(http://your-repo/repository/android/) credentials { username admin password admin } } } }对于 Android 工程AAR 包的产出路径一般在build/outputs/aar/下你需要根据模块名和构建变体调整上面的artifact()路径。也可以写得聪明一点动态拼接def aarPath $buildDir/outputs/aar/${project.name}-release.aar if (file(aarPath).exists()) { artifact(aarPath) }发布命令也从gradle uploadArchives改为gradle publish如果想发布到本地 Maven 仓库比如mavenLocal()在repositories里加一个mavenLocal()然后执行gradle publishToMavenLocal生成的 AAR/JAR 和 POM 文件会放在本机~/.m2/repository对应目录下。很多人在内网环境开发时会用到这一招。提示如果你之前用maven插件是为了把依赖装到本地仓库供其他模块引用现在也可以换成publishing加mavenLocal()的组合效果完全等价而且不用碰沿用多年的老脚本。3.3 新旧配置对照速查表为方便你直接照抄我把老写法和新写法整理成了对照表功能老插件maven新插件maven-publish应用插件apply plugin: mavenapply plugin: maven-publish定义发布信息uploadArchives { repositories.mavenDeployer { pom.groupId ... } }publishing { publications { mavenJava(MavenPublication) { groupId ... } } }发布到远程仓库使用repository(url: ...)authentication使用repositories { maven { url uri(...) credentials { ... } } }发布到本地默认install任务或额外配置直接配置mavenLocal()用publishToMavenLocal执行命令gradle uploadArchivesgradle publish生成 POM自动通过pom扩展配置MavenPublication自动生成可加pom.withXml自定义我个人的建议是如果工程还要长期维护干脆统一迁到maven-publish。老插件不仅名字没了连它在 Gradle 8.x 下的 API 行为也已经失宠继续坚持老写法等于给自己埋雷。4. 解决方案二老项目不想改代码怎么临时规避4.1 锁定 Gradle 版本有些项目非常老里面的uploadArchives配置复杂到你不能轻易动或者发布脚本是别的团队维护的改不动。此时不改项目改环境是合理的临时方案。核心思路就是把 Gradle 版本降到仍然支持maven插件的版本。比如 Gradle 6.9 及以下版本还保留老插件。对应 Android Gradle Plugin常用组合Android Gradle Plugin 版本配套 Gradle 版本AGP 3.xGradle 4.10 ~ 6.xAGP 4.0 ~ 4.2Gradle 6.1 ~ 7.xAGP 7.0Gradle 7.0 ~ 7.4AGP 7.4Gradle 7.5修改位置在gradle/wrapper/gradle-wrapper.propertiesdistributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://services.gradle.org/distributions/gradle-6.9-bin.zip zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/dists只要把distributionUrl改成目标版本再执行gradle wrapper --gradle-version 6.9重新同步项目就能绕开UnknownPluginException。这个方法对于遗留项目最省事因为它不需要改任何业务构建脚本只调整构建工具版本。注意降版本可能会触发其他兼容性问题比如 AGP 过高、Java 版本不匹配、依赖插件不支持等。所以锁定版本前先查一下你当前 AGP 版本对应的最低/最高 Gradle 版本找一个中间值。别一上来就把 Gradle 降到 4.x那对 JDK 环境的要求又会变。4.2 如果报错藏在第三方插件内部有些情况下你不好改第三方插件内部的逻辑但你又不能降版本比如你依赖了必须运行在新 Gradle 上的其他插件那可以试试在项目根构建脚本中提前包装一个同名的占位插件。具体思路是在buildSrc或者根脚本里自定义一个 ID 为maven的插件类内部转发到maven-publish的实现。这种方案在某些私有插件冲突上确实有用但只适合有一定 Gradle 插件开发经验的读者尝试而且临时性极强长期维护不推荐。我更推荐的做法是升级出问题的第三方依赖。如果这个依赖是老版本 SDK 的 Gradle 插件去官网找新版新版基本都迁移到了maven-publish。这一点在 Flutter 项目里表现尤其明显老版本 Flutter 项目的 Gradle 脚本往往写着老式写法升级 Flutter 后 AGP 和 Gradle 版本都变了老脚本自然不兼容适当升级后问题自动消失。4.3 临时修改第三方脚本的办法如果你能通过gradle依赖缓存定位到第三方插件所在的 jar 包路径也可以解压后改里面的.gradle脚本再重新打包。这个方案比较暴力我这里不展开因为更新依赖版本往往是更干净的选择。只有当你在离线内网环境、依赖无法升级时才考虑通过篡改缓存脚本的方式应急。5. 环境问题排查镜像、下载失败与离线包5.1 配置国内镜像源搜UnknownPluginException的不少人是顺着 Gradle 下载、Maven 仓库等热词摸过来的也就是说很多人同时遇到了插件仓库解析不到、下载超时的附加问题。虽然镜像配置治不了maven插件被移除这个根因但确实能让整体构建更顺利尤其当你依赖的插件需要从gradlePluginPortal()拉取时。常见的国内镜像地址包括阿里云公共仓库https://maven.aliyun.com/repository/public阿里云 Gradle 插件仓库https://maven.aliyun.com/repository/gradle-plugin腾讯云镜像https://mirrors.cloud.tencent.com/nexus/repository/maven-public/在settings.gradle的pluginManagement仓库里加上这些地址能显著提升插件下载速度pluginManagement { repositories { maven { url https://maven.aliyun.com/repository/gradle-plugin } maven { url https://maven.aliyun.com/repository/public } maven { url https://maven.aliyun.com/repository/google } gradlePluginPortal() google() mavenCentral() } } dependencyResolutionManagement { repositories { maven { url https://maven.aliyun.com/repository/public } maven { url https://maven.aliyun.com/repository/google } maven { url https://maven.aliyun.com/repository/gradle-plugin } google() mavenCentral() } }对于使用 Groovy DSL 的老项目如果没有settings.gradle只有settings.gradle没有 pluginManagement可以在build.gradle的buildscript仓库里加镜像buildscript { repositories { maven { url https://maven.aliyun.com/repository/public } maven { url https://maven.aliyun.com/repository/google } maven { url https://maven.aliyun.com/repository/gradle-plugin } google() mavenCentral() } dependencies { classpath com.android.tools.build:gradle:4.2.2 } }提示这里有一个老生常谈的坑——镜像地址别写错比如maven.aliyun.com/repository/public和maven.aliyun.com/repository/central是两个不同的仓库前者聚合了中央仓库和其他常见仓库后者只代理中央仓库。全用public通常问题不大。5.2 Gradle 下载慢或失败的解决思路很多新人在gradle-wrapper.properties里看到的分发地址是services.gradle.org/distributions/...这个地址在国内访问经常卡住甚至失败于是冒出来一堆 每次新建项目都要下载 Gradle 的求助。解决方式很简单方式一修改 distributionUrl 为国内镜像。腾讯和阿里都有 Gradle 发行包镜像比如腾讯镜像的格式distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-7.5-bin.zip方式二手动下载 Gradle 离线包并放到指定目录。你可以先找一台网络正常的机器把对应版本的gradle-x.x-bin.zip下载好然后放到本地的 Gradle wrapper 缓存目录WindowsC:\Users\你的用户名\.gradle\wrapper\dists\gradle-x.x-bin\...macOS / Linux~/.gradle/wrapper/dists/gradle-x.x-bin/...放进去之后再用 Android Studio 同步项目它校验完文件就直接解压不需要再走网络。很多人管这个叫 Gradle 离线包实际上就是把 wrapper 分发包预先塞进缓存。如果你希望全局使用同一个 Gradle 版本也可以直接下载完整 Gradle 发行包解压后配置AS里的 Gradle 路径为本地目录而不是用 wrapper 下载。5.3 Android Studio 中文设置与 SDK 环境补充搜索记录里很多和android studio、sdk相关的内容其实是在旁敲侧击环境配置问题。如果你刚装了 Android Studio建议先顺手确认三件事JDK 版本Gradle 7.x 要求 JDK 11Gradle 8.x 要求 JDK 17老项目配新 JDK 也可能出现莫名其妙的脚本错误。SDK 路径Android Studio 里File - Settings - Appearance Behavior - System Settings - Android SDK确认 SDK Platforms 和 SDK Tools 都勾选完毕。中文设置设置面板里搜索Appearance在Language区域切换为中文后重启即可这个不影响构建纯属个人偏好。环境顺了排查UnknownPluginException这类构建问题时才能集中火力。6. 常见问题与排查技巧实录6.1 问题速查表我在实际踩坑过程中整理了下面几条高频问题的判断方向和解决办法现象可能原因处理方向Plugin with id maven not found项目用了老maven插件Gradle 7 已移除改为maven-publish或降 Gradle 版本Could not find method mavenDeployer()已切到新插件但发布代码还是老写法迁移uploadArchives为publishing依赖仓库下载特别慢默认访问国外仓库配置阿里云/腾讯镜像Could not install Gradle distribution from ...Gradle 发行包下载失败换国内镜像下载地址或使用离线包Deprecated Gradle features were used in this build脚本用了老 API按提示替换为推荐写法或临时加--warning-mode all查看明细Flutter 项目报apply flutters main gradle plugin imperativelyFlutter 脚本和 AGP/Gradle 版本不匹配升级 Flutter 插件或调整 Gradle 版本6.2 一次真实的多模块排查经历有一回我处理一个老 SDK 的工程报错信息指向的是:common模块。全局搜索maven后发现common/build.gradle里确实写了apply plugin: maven。顺手改了插件名结果接着报了mavenDeployer找不到。这才发现里面还配置了一大段老发布逻辑。当时项目不能降 Gradle 版本因为另一个核心模块依赖的新插件只支持 Gradle 7所以只能花一个小时把发布逻辑整体迁到publishing。迁移的经验是先删掉uploadArchives整个块再重新写publishing { publications { ... } }。不要试图逐个属性翻译那样容易漏。写完后执行gradle publishToMavenLocal然后去~/.m2/repository下确认生成的 POM 文件和 AAR 产物路径是否正确一次性验证到位。6.3 使用--stacktrace定位更深层的问题如果改完插件名后还有报错建议执行gradle build --stacktrace --info--stacktrace能打出完整调用链--info能输出每一步配置细节。很多隐藏的脚本错误比如某个变量在脚本解析阶段还未定义、某个仓库地址写法不对都会直接暴露在调试日志里。还有一个实用技巧在settings.gradle或build.gradle开头临时加一行logger.lifecycle(project dir: ${projectDir})可以在每个模块配置阶段打出当前评估的是哪个模块配合报错信息能快速锁定问题模块特别是当你面对一个有着几十个模块的大型 Android 工程时这招比人肉搜索高效得多。6.4 其他容易被忽略的坑插件声明重复同一个模块里同时用apply plugin: maven和plugins { id maven }也可能触发未知插件异常因为plugins块只能在顶层脚本中使用且不能用在子模块的apply plugin之前。仓库地址未配置某些项目只配了google()和mavenCentral()没有mavenLocal()导致本机仓库里的私有构件解析不到构建时把报错嫁祸给插件解析失败。检查repositories时要全面。分支切换后 Gradle 版本不一致从另一个分支拉代码后gradle-wrapper.properties变了本地 Gradle 版本和缓存不匹配建议在 Android Studio 里执行一次File - Sync Project with Gradle Files让 wrapper 重新解压。项目里残留.gradle缓存某些诡异的 找不到插件 问题可以通过执行gradle clean或删除项目根目录下.gradle文件夹缓解但注意别删~/.gradle里的全局缓存除非你想重新下一遍。7. 写在最后我的实际体会我个人在处理这类构建问题时最深的一点体会是不要先急着改代码而是先把 Gradle 版本和插件对应关系搞清楚。很多 Android 开发同学遇到UnknownPluginException就习惯性去仓库配置和镜像里找原因实际上大部分情况下是 Gradle 7 以上版本把老maven插件移除了属于版本演进带来的兼容性阵痛。如果你手头是一个长期维护的工程我强烈建议直接迁移到maven-publish不要想着用降版本的方式拖下去。老插件不仅名字没了配置模型也和新版本脱节拖着只会让后续升级越来越痛苦。反过来如果只是一个短期遗留分支或者发布逻辑属于不可控的第三方脚本那锁定 Gradle 版本作为临时方案完全合理但要记得在项目的 README 或者注释里留一句说明免得后来的人再踩一次坑。最后分享一个小技巧解决完插件报错后顺手看一眼gradle --version输出的Kotlin版本因为 Kotlin DSL 项目里插件解析失败有时会和 Kotlin 编译器的版本警告混淆。把 Gradle、AGP、JDK 和 Kotlin 的版本形成一张固定的组合表写进团队文档以后排查同类问题的时候能节省至少半天时间。