最近连续有好几个人跑来问我同一个问题:用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目录下的资源,通常还会跑AAPT2
- compileDebugJavaWithJavac 或 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占用为0 | Gradle进程未存活 | 检查JDK与Gradle配置 |
| 卡在某个具体compileTask | Kotlin/Java编译阻塞 | 检查JDK版本与增量编译缓存 |
拿着这张表对照自己日志末尾的输出,基本三分钟就能锁定方向。
2.2 检查Gradle守护进程状态
Gradle默认会启动一个常驻的守护进程(Daemon),用来避免每次构建都重新加载所有依赖和配置。这个设计大大提升了构建速度,但也带来一个隐患:如果Daemon因为内存不足或配置被改成卡死,后续所有构建都会排队等待同一个Daemon,表现就是你看到的"卡在assembleDebug"。
遇到这种情况,先查一下Daemon状态:
gradlew --status输出里会列出所有存活Daemon的PID、JVM版本和状态。如果你发现Daemon状态是BUSY但项目根本没有在执行任何任务,或者内存参数明显不对,直接停掉再构建:
gradlew --stop停掉之后重新执行assembleDebug,Gradle会拉起一个全新的Daemon。很多莫名其妙的卡死,重启Daemon后就自然消失了。
3. 头号元凶:Gradle发行包下载不动,换镜像一劳永逸
说完了定位方法,现在聊最高频的原因:Gradle发行包下载卡死。这个坑对新电脑、新环境、刚拉下来的项目几乎是必踩,因为它发生在构建流程的最前面,一旦卡住,后面所有任务都无从谈起。
3.1 为什么首次构建要下载Gradle发行包
每个Android项目里都有一个gradle/wrapper/gradle-wrapper.properties文件,内容大概是这样的:
distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/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改为国内镜像地址。我实测过两个稳定可靠的镜像源:
# 腾讯云镜像 distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.13-bin.zip # 华为云镜像 distributionUrl=https\://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改成本地文件路径:
distributionUrl=file\:/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 Plugin(AGP)、Gradle发行版、JDK。任何一个齿轮错位,构建就会卡住或者直接报错退出。
5.1 不同AGP版本对应的Gradle与JDK
我整理了一份常用版本对应表,基本上你遇到的大多数项目都能在这张表里对号入座:
| AGP版本 | 最低Gradle版本 | 推荐JDK版本 |
|---|---|---|
| AGP 8.6 / 8.7 | Gradle 8.9+ | JDK 17 |
| AGP 8.2 / 8.3 | Gradle 8.2+ | JDK 17 |
| AGP 8.0 / 8.1 | Gradle 8.0+ | JDK 17 |
| AGP 7.4 | Gradle 7.5+ | JDK 11 |
| AGP 7.2 / 7.3 | Gradle 7.3.3+ | JDK 11 |
| AGP 7.0 / 7.1 | Gradle 7.0+ | JDK 11 |
| AGP 4.2 及更早 | Gradle 6.7.1+ | JDK 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.properties:
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError把最大堆内存调到4GB,元空间调到1GB,在多数中大型项目里都够用了。如果你的机器只有8GB内存,建议同时加上:
org.gradle.parallel=true org.gradle.caching=true并行构建和构建缓存能显著减少任务等待时间。机器内存小于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'"发呆的深夜。