Gradle构建卡在assembleDebug?从下载到依赖再到版本匹配全排查
最近连续有好几个人跑来问我同一个问题用Android Studio生成APK底部进度条一直停在Running Gradle task assembleDebug...等半小时都不动最后只能把Android Studio强退。这问题我太熟了早期做跨平台项目移植的时候几乎每个新环境都要踩一遍。卡在这个位置的本质其实不是Android Studio坏了而是它背后的Gradle构建流程被某个环节堵住了——多半是下载、依赖、版本匹配或资源处理出了问题。这篇文章就把我这些年的排查思路和解决方案完整写出来覆盖从Gradle发行包下载到AGP版本匹配再到构建内存的全链路适合所有被assembleDebug卡住的开发者直接对照操作。1. 卡在assembleDebug先搞清楚Gradle到底在执行什么1.1 assembleDebug不是一键打包而是一条任务链很多初学者误以为点击Build APK就是在做一次类似压缩文件的简单操作其实assembleDebug是Gradle任务树里的一个聚合任务。它的全名是assemble Debug变体触发后会按依赖关系依次执行几十个任务我随便列几个你就能感受到这个链条有多长preBuild构建前检查包括校验SDK版本、Build-Tools版本mergeDebugResources / processDebugResources合并并处理res目录下的资源通常还会跑AAPT2compileDebugJavaWithJavac 或 compileDebugKotlin编译Java/Kotlin源码dexBuilderDebug把class文件压缩成DEX字节码packageDebug打个未签名的APK包signingConfig 相关任务完成APK签名所以当界面显示Running Gradle task assembleDebug时Gradle实际可能正卡在上述任意一个环节。进度条不涨不代表死机它更可能是某个子任务在默默等待下载、等待远程仓库响应或者等待系统资源。搞清楚这一点就不会病急乱投医到处重装Android Studio了。1.2 进度条不动先做三个快速判断在决定改任何配置之前我建议你先花两分钟做三个检查能省下后面大量无用功第一看Build工具窗口是否有新日志。Android Studio底部切到Build窗口如果日志还在滚动说明任务链还在推进只是UI刷新跟不上。此时只需要耐心等待不必干预。第二打开系统任务管理器Windows或活动监视器Mac找到名字里带Gradle或Java的进程观察它的CPU占用率和网络收发速度。CPU持续占用说明Gradle在跑任务网络有持续流量说明它在下载东西两者都几乎为零那才是真的卡死了。第三确认一下当前网络是否正常。很多时候卡死在Downloading环节是因为公司网络或校园网对某些境外域名的访问不稳定这个问题在后面镜像章节我会给根治方案。顺便提醒一句如果你发现Build窗口里连Downloading gradle-xxx-bin.zip这行提示都没出现那么问题可能根本不是卡住而是Gradle进程压根没起来或者Android Studio的Gradle配置指向了一个不存在的路径。这种情况下优先检查File - Settings - Build, Execution, Deployment - Build Tools - Gradle里选中的Gradle版本。2. 定位卡点两种日志粒度判断Gradle卡在哪一步有了上面的初步判断接下来就要精确定位。我见过太多人一上来就照着网上的教程乱改镜像配置结果问题根本不是镜像浪费一下午。定位卡点最可靠的办法就一条让Gradle把日志吐出来给你看。2.1 用命令行构建强制输出完整日志Android Studio自带构建窗口显示的日志是精简过的经常只显示一行Running Gradle task assembleDebug卡住后你什么都看不清。正确的做法是打开项目根目录用命令行直接构建# Windows在项目根目录执行 gradlew.bat assembleDebug --info # macOS / Linux执行 ./gradlew assembleDebug --info--info参数会把每一个Task的执行状态、耗时、依赖解析过程全部打印出来。同样是卡住日志末尾的关键字完全不同我总结过一个速查表日志关键字 / 表现卡点类型处理方向Downloading Gradle distribution... 长时间不动Gradle发行包下载换国内镜像或手动放包Could not GET / Could not resolve dependencies依赖仓库访问失败换Maven镜像仓库Waiting for lock on daemon / daemon busy守护进程僵死或内存不足停掉daemon调大JVM内存 Task :app:processDebugResources 卡住AAPT2/资源处理检查SDK Build-Tools、清理缓存没有任何输出CPU占用为0Gradle进程未存活检查JDK与Gradle配置卡在某个具体compileTaskKotlin/Java编译阻塞检查JDK版本与增量编译缓存拿着这张表对照自己日志末尾的输出基本三分钟就能锁定方向。2.2 检查Gradle守护进程状态Gradle默认会启动一个常驻的守护进程Daemon用来避免每次构建都重新加载所有依赖和配置。这个设计大大提升了构建速度但也带来一个隐患如果Daemon因为内存不足或配置被改成卡死后续所有构建都会排队等待同一个Daemon表现就是你看到的卡在assembleDebug。遇到这种情况先查一下Daemon状态gradlew --status输出里会列出所有存活Daemon的PID、JVM版本和状态。如果你发现Daemon状态是BUSY但项目根本没有在执行任何任务或者内存参数明显不对直接停掉再构建gradlew --stop停掉之后重新执行assembleDebugGradle会拉起一个全新的Daemon。很多莫名其妙的卡死重启Daemon后就自然消失了。3. 头号元凶Gradle发行包下载不动换镜像一劳永逸说完了定位方法现在聊最高频的原因Gradle发行包下载卡死。这个坑对新电脑、新环境、刚拉下来的项目几乎是必踩因为它发生在构建流程的最前面一旦卡住后面所有任务都无从谈起。3.1 为什么首次构建要下载Gradle发行包每个Android项目里都有一个gradle/wrapper/gradle-wrapper.properties文件内容大概是这样的distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://services.gradle.org/distributions/gradle-8.13-bin.zip zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/distsGradle Wrapper机制的设计意图是不依赖开发者本机安装的Gradle版本而是由项目自己锁定一个Gradle版本首次构建时按照distributionUrl指定的地址把这个版本的Gradle压缩包下载到用户目录下的.wrapper/dists文件夹里然后解压使用。换句话说你拉下一个新项目只要是第一次在这个电脑上构建就必然去官方地址下载一次Gradle发行包。问题就出在这个官方地址上。services.gradle.org是一个境外服务国内网络环境下下载几MB还凑合但Gradle发行包动辄一百多MB下载速度一旦降到几十KB/s整个构建就会在Downloading Gradle distribution...这一步卡上十几分钟甚至更久。你看到的assembleDebug进度条一大半时间都耗在这里。3.2 方案一修改distributionUrl替换为国内镜像最省事也最彻底的方案把distributionUrl改为国内镜像地址。我实测过两个稳定可靠的镜像源# 腾讯云镜像 distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-8.13-bin.zip # 华为云镜像 distributionUrlhttps\://mirrors.huaweicloud.com/gradle/gradle-8.13-bin.zip改完之后保存文件重新执行构建。Gradle发现distributionUrl变了会去镜像地址重新下载速度通常能到几MB/s甚至更高。有一点要特别注意镜像地址的版本号必须和原文件完全一致你想把8.13改成8.11之前先确认项目的AGP插件支持哪个Gradle版本别为了追求版本号高就乱改。3.3 方案二手动下载离线包直接塞进Wrapper目录如果你所在网络连镜像都访问不畅或者你希望彻底摆脱每次新项目都要下载Gradle的烦恼可以走离线包路线。先手动下载对应版本的gradle-8.13-bin.zip找个能访问的机器或手机热点下载都行然后放到Gradle用户目录的缓存路径下。具体路径是这个结构C:\Users\你的用户名\.gradle\wrapper\dists\gradle-8.13-bin\一长串哈希值\这串哈希值是Gradle根据distributionUrl计算出来的每个人机器上可能不一样。更省心的办法是先在gradle-wrapper.properties里把distributionUrl改成本地文件路径distributionUrlfile\:/D:/soft/gradle-8.13-bin.zip保存后再构建一次Gradle会直接把本地zip解压使用完全不走网络。等它跑起来之后你再把distributionUrl改回镜像或官方地址因为此时解压好的Gradle已经缓存在本地后续构建不会再重新下载。3.4 方案三用Android Studio自带的Gradle绕开Wrapper下载Android Studio安装目录下的plugins/gradle/lib里自带了一个Gradle发行版如果你不想下载任何东西在File - Settings - Build Tools - Gradle里把Use Gradle from改成Specified location然后手动选择Android Studio自带的Gradle目录。这样Gradle Wrapper就不会触发下载逻辑直接从本地加载。这个方法适合急用时快速绕过但它有个明显缺点项目wrapper属性里锁定的Gradle版本和Android Studio自带的版本可能不一致版本差距过大会导致AGP插件报不支持的错误。所以它更适合临场救急长期方案还是建议修改distributionUrl用镜像源或离线包。4. 依赖拉不下来仓库镜像配置的正确姿势如果Gradle发行包已经下载成功、构建也确实启动了但仍然卡住很久下一个排查重点是依赖仓库。Android项目依赖了成百上千个来自Google官方Maven仓库和Maven Central的库这些仓库的域外访问状况大家都懂依赖解析卡个5分钟10分钟非常常见。4.1 新版AGP的仓库配置位置变了很多老教程会让你在项目根目录的build.gradle里写allprojects { repositories { ... } }这个写法在AGP 7.0之前的项目里没毛病但新版Android Studio创建的项目仓库配置已经被挪到了settings.gradle里用dependencyResolutionManagement统一管理dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }如果你还在老的allprojects里配置镜像新版AGP会直接报错或者忽略你的配置这就是为什么很多人改了镜像却一点效果都没有。4.2 阿里云镜像推荐配置正确的做法是把settings.gradle里的仓库地址替换为阿里云Maven镜像。阿里云镜像源把Google仓库和Maven Central都做了同步我用的是这套组合dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 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 } maven { url https://maven.aliyun.com/repository/central } google() mavenCentral() } }把阿里云镜像放在google()和mavenCentral()之前Gradle解析依赖时会优先访问镜像地址只有镜像里找不到的冷门库才会回源到官方仓库。这套配置对绝大多数项目足够用了尤其是用到了AndroidX库、第三方SDK的项目依赖解析速度会有肉眼可见的提升。这里写个小提示:如果你的项目是几年前的旧项目用到了jcenter()阿里云也提供了jcenter镜像maven { url https://maven.aliyun.com/repository/jcenter }。虽然JCenter已经停止更新但老项目的存量依赖仍然可以从镜像拿到。4.3 个别依赖仍失败时的兜底手段镜像配置完成后偶尔还是会遇到个别库解析失败常见原因是该库只在某个特定仓库发布阿里云没同步到或者mirror本身正在更新。这种时候我的兜底方案有两个一是用Gradle的离线模式配合预缓存。找一台网络环境好的机器先把项目完整构建一遍然后打开Android Studio的File - Settings - Build Tools - Gradle勾选Offline work。构建时Gradle不再访问任何远程仓库只用本机缓存如果缓存里已经有这个项目的全部依赖构建速度反而比以前更快。适合在无网络或弱网环境编译。二是手动下载依赖包放到libs目录。定位到是哪个依赖解析失败从仓库手动下载对应的.aar或.jar文件放进app/libs目录然后在build.gradle里用implementation files(libs/xxx.aar)引用。这个方法丑但能解决大部分镜像都救不了的边缘问题。5. 版本匹配表AGP、Gradle、JDK三者的齿轮关系排查完下载和依赖架构层面的最后一个高频坑是版本匹配。Android构建链路里三个核心版本必须像齿轮一样咬合Android Gradle PluginAGP、Gradle发行版、JDK。任何一个齿轮错位构建就会卡住或者直接报错退出。5.1 不同AGP版本对应的Gradle与JDK我整理了一份常用版本对应表基本上你遇到的大多数项目都能在这张表里对号入座AGP版本最低Gradle版本推荐JDK版本AGP 8.6 / 8.7Gradle 8.9JDK 17AGP 8.2 / 8.3Gradle 8.2JDK 17AGP 8.0 / 8.1Gradle 8.0JDK 17AGP 7.4Gradle 7.5JDK 11AGP 7.2 / 7.3Gradle 7.3.3JDK 11AGP 7.0 / 7.1Gradle 7.0JDK 11AGP 4.2 及更早Gradle 6.7.1JDK 8 / 11在实际操作中怎么知道项目用的是什么版本AGP版本号在项目根目录build.gradle或libs.versions.toml里能看到Gradle版本在gradle/wrapper/gradle-wrapper.properties的distributionUrl里JDK版本则看Android Studio的File - Settings - Build Tools - Gradle - Gradle JDK下拉框。5.2 版本错位时的典型报错逻辑版本不匹配在卡住之前通常会有明确的报错提示但很多人看到报错就慌没去读内容。最常见的两类报错如下Minimum supported Gradle version is 8.2. Current version is 7.5.看到这行说明Gradle版本太旧AGP要求至少8.2但你用的还是7.5。解决办法是去gradle-wrapper.properties里把distributionUrl改成更高版本或者反过来降低AGP版本总之让两者落在上表对应区间内。另一类报错是Unsupported class file major version 61这是JDK版本和Gradle/AGP不匹配的标志——61对应JDK 17。项目要求JDK 11而你用了JDK 17或反过来项目需要JDK 17而Gradle配置成了JDK 11都会出现这类报错。处理方式是在Android Studio的Gradle JDK设置里切换到对应版本。表里推荐JDK版本是我反复验证过的稳妥选择。这里多提一句用Android Studio自带JBR通常不会遇到JDK问题除非你手动改过Gradle JDK下拉框指向了系统安装的其它JDK版本。还有一类情况是升级Android Studio之后AS提示你更新AGP插件版本。如果你点了更新AGP版本跳到了8.x但Gradle和JDK还是老项目的旧版本构建就会突然卡住或直接报错。这就是为什么我最常说升级IDE之前先看清楚项目的AGP、Gradle、JDK三个版本是不是匹配。5.3 换电脑移植项目的版本陷阱前面提到过移植Android Studio项目这里特别提醒从别人那里拷贝或从Git拉下来的项目最容易出现版本错位。因为每个项目的gradle-wrapper.properties锁定的Gradle版本是写死的而对方机器上JDK和SDK的位置、版本乃至gradle缓存的内容都跟你不一样。拉下老项目后不要急着点那个绿色的运行按钮先看一眼wrapper里的Gradle版本和AS设置里的Gradle JDK再决定要不要动手构建。6. 构建内存、守护进程和SDK路径那些容易忽略的隐性坑解决了下载、依赖和版本这三个大块头还有一批看起来不是问题但实际很坑的细节。它们在日志里不明显却会让构建卡得毫无征兆。6.1 gradle.properties里的JVM参数调优构建项目时Gradle会启动一个独立的JVM进程这个进程的内存上限默认只有1.5GB左右。如果你的项目依赖特别多Kotlin编译又吃内存构建过程中频繁触发Full GC表现就是CPU忙但进度极慢近乎卡死。改一下项目根目录的gradle.propertiesorg.gradle.jvmargs-Xmx4096m -XX:MaxMetaspaceSize1024m -XX:HeapDumpOnOutOfMemoryError把最大堆内存调到4GB元空间调到1GB在多数中大型项目里都够用了。如果你的机器只有8GB内存建议同时加上org.gradle.paralleltrue org.gradle.cachingtrue并行构建和构建缓存能显著减少任务等待时间。机器内存小于8GB的话4GB的堆内存可能会挤占系统资源可以降到-Xmx2048m但至少不要停留在默认的1.5G。6.2 构建缓存损坏导致的任务假死Gradle会把每个Task的输入输出缓存起来以便增量构建。如果缓存文件损坏强制关机、磁盘空间不足、杀毒软件误删都是诱因某些Task会不停地重新执行甚至卡死。这类问题很难从日志直接看出来最有效的处理就是清理缓存后重建gradlew clean如果clean还解决不了直接把Gradle用户目录下的caches文件夹改名备份让Gradle重新生成全部缓存。路径一般在C:\Users\你的用户名.gradle\caches。删除后首次构建会慢一点因为所有依赖要重新解析但至少能绕过损坏的缓存文件。6.3 SDK Build-Tools与Platform缺失卡在processDebugResources这类资源处理任务时除了缓存问题还要检查SDK组件是否齐全。Android Studio倾向于自动下载缺失的SDK组件但在某些网络环境下这个自动下载同样会卡住不报错。去File - Settings - Appearance - System Settings - Android SDK里确认SDK Platforms里有没有安装compileSdkVersion对应的平台版本SDK Tools里Build-Tools有没有安装项目要求的版本如果发现缺失勾选后点击Apply手动下载。下载慢的话就换个时段再试这个没法走Maven镜像只能靠网络自己扛。6.4 中文路径、杀毒软件、代理残留的三重干扰最后说三个当年的血泪坑。中文用户名或中文项目路径会让Gradle在某些Task上出现编码相关的奇怪失败而且不是每次都复现极难排查。如果你Windows用户名本身是中文至少保证项目路径是纯英文比如D:/AndroidProjects/MyApp。杀毒软件实时监控可能会扫描Gradle正在写入的缓存文件导致构建线程被拖死。如果你开了360、火绒之类的实时防护构建时把gradle用户目录和项目目录加进信任列表或者干脆在构建期间暂停防护。别问为什么问就是Gradle构建期间那几百MB的缓存文件写入足够把杀毒引擎跑满。代理残留是另一个隐蔽问题。如果你曾经在gradle.properties里配置过网络代理后来换了网络环境但忘记删掉Gradle会持续尝试连接早已失效的代理地址。检查一下gradle.properties里是不是还有类似systemProp.http.proxyHost、systemProp.https.proxyHost这样的配置有就删掉再重启构建。这个很关键因为类似配置在Android Studio里看不到只藏在项目文件里。还有一个关于Daemon权限的细节如果在Windows上用管理员权限打开终端执行gradlew构建之后再用Android Studio普通权限构建两个环境的Daemon会因为权限上下文不一致而冲突最典型的症状是卡在Waiting for lock on daemon。解决方案就是再执行一次gradlew --stop把所有Daemon清掉重新来。结尾用我的习惯动作给这套排查收个尾这些年在多个电脑环境、多个项目上反复踩assembleDebug这个坑我养成了一个固定的动作遇到卡死第一反应不是改代码而是打开命令行跑gradlew assembleDebug --info先看一眼日志尾巴在说什么。下载问题看镜像依赖问题看仓库配置报错看版本号不报错但不动看Daemon和内存这条链路走完基本上十之八九都能精准治好。我的个人建议是把镜像配置和版本匹配表这两件事当成新环境初始化时必须做的事不要等项目卡了才想起来。gradle-wrapper.properties里先换成国内镜像地址settings.gradle里配好阿里云仓库再确认AGP、Gradle、JDK三者匹配后面你会发现assembleDebug这条路顺得让人心情舒畅。希望这篇文章能帮你少熬几个对着Running Gradle task assembleDebug发呆的深夜。