
最近在一个老项目上又碰见了这个折腾人的问题Build 窗口卡在Downloading https://services.gradle.org/distributions/gradle-7.6-all.zip几十分钟过去进度纹丝不动偶尔还会直接抛一个SocketTimeoutException。可能很多人一看到Downloading就以为是项目坏了想重装 Android Studio、删掉.gradle文件夹甚至把整台电脑的东西都清理一遍。其实这是 Gradle Wrapper 在为你的项目下载指定版本的 Gradle 发行包而下载源默认用的是官方地址services.gradle.org。如果你所在网络环境访问这个官方源不稳定那就很容易卡在这一步。这篇文章我会把这条日志的来龙去脉讲清楚再给你几条实测有效的解决路径换成腾讯云/华为云镜像、改 all 为 bin 减少体积、手动下载后用本地文件路径喂给 Wrapper以及在团队和 CI 环境里怎么统一配置。最后会整理一份常见报错排查表包括那类“Gradle 版本和 JVM 版本不兼容”的连带问题。不管你是刚接触 Gradle还是被这个下载问题折腾过几次都可以直接按步骤操作。1. 先看这一行日志Gradle Wrapper 在替你下载运行时环境1.1 Wrapper 到底是什么很多人把 Gradle 当成 Android 项目的“编译插件”其实它本身是一个独立构建工具你需要先有一份 Gradle 运行环境才能执行构建任务。问题是一台电脑可能要同时维护多个项目每个项目要求的 Gradle 版本又未必一样你不可能每次都手动改系统全局版本。于是 Gradle 官方给出了 Wrapper 机制。项目里通常没有完整的 Gradle 目录只有几个文件gradlew、gradlew.bat和gradle/wrapper/gradle-wrapper.properties。执行./gradlew时这个脚本会先检查本机用户目录里有没有指定版本的 Gradle没有的话就按distributionUrl去下载下载完再解压、缓存之后每次构建都会复用本地缓存。所以那句Downloading https://services.gradle.org/distributions/gradle-7.6-all.zip其实是个非常正常的提示表示当前机器上还没有缓存 gradle-7.6 这个发行包。常见场景分三种一是第一次拉项目到本地二是从别的机器迁移来还没有生成~/.gradle缓存目录三是 CI 流水线每次跑在全新的容器里。只要缓存没命中Wrapper 就必须去下载。真正需要警惕的是下载过程一旦长时间无进展或者直接报连接超时那就说明官方源或网络链路有瓶颈这时候你再怎么点同步都没用因为卡点在下载步骤本身。1.2 all 和 bin同样版本为什么有的项目是 all你看到的 URL 末尾是gradle-7.6-all.zip但同一版本还有gradle-7.6-bin.zip。两者包含的可执行构建逻辑是一样的区别在于 all 包额外带了 Gradle 的源码、文档和示例。我们绝大多数日常项目根本不需要这些源码编译任务用 bin 就能完整执行。很多 Android / Flutter 模板项目默认配置成 all也许是为了开发者 Debug 时能查看 Gradle 内部实现但这会带来一个副作用下载体积比我说的 bin 包大不少所有包越大在网络不稳定的情况下就越容易失败。你打开gradle-wrapper.properties后如果看到 all可以先想一下这个项目到底需不需要看 Gradle 自身源码如果不需要完全可以把-all.zip改成-bin.zip。改完之后建议顺便检查有没有distributionSha256Sum这一行。如果项目里配置了校验和那么你修改了发行包类型之后本地构建会重新校验旧校验和显然不匹配。安全一点的做法是把校验和行临时删掉等网络环境正常后再找你实际拿到的 bin 包对应哈希值补回来。对于本地开发的个人项目删掉这一行影响不大如果是团队共用的仓库建议配合镜像统一再校验一次。2. 为什么会一直卡住官方源、缓存与下载重试逻辑2.1 下载源远、文件大是最常见的原因services.gradle.org是 Gradle 官方对外提供发行包的域名。对于跨境访问、企业内网限速、或运营商路由不稳的场合经常出现小文件能打开、大文件下到一半就断的情况。而gradle-7.6-all.zip是一个体积不小的大安装包下载时间越长受网络波动影响越大。所以很多时候不是服务端挂了而是“大文件长连接”在路由较长的链路上更容易失败。这类问题的典型报错如下Could not install Gradle distribution from https://services.gradle.org/distributions/gradle-7.6-all.zip. Reason: java.net.SocketTimeoutException: connect timed out看到SocketTimeoutException基本就是建立连接超时而不是编译出错。还有一个常见表现是终端卡在下载行不动没有报错进度条也不走。这时候首先要确认目标下载源到底能不能连通我通常会开另一个终端先用curl看一眼响应头curl -I https://services.gradle.org/distributions/gradle-7.6-all.zip如果命令结果迟迟不返回或者出现连接重置、超时这类报错那就基本可以判断官方源在你的网络环境下“不好用”。这时候别死磕改用镜像源是更现实的做法。注意下载失败后 Wrapper 不一定会保留有效的断点进度。很多版本会在失败后清理不完整的临时文件你重新执行./gradlew时仍然从零开始。多次失败、重试、再失败会给人的感觉是“项目彻底卡死了”。所以在调整方案之前先停掉正在跑的构建任务避免它继续占据网络和缓存目录。2.2 你以为没下载完其实是缓存目录出问题另一种“每次都下载”的假象和下载源没关系。Gradle Wrapper 的下载缓存默认放在用户目录下的.gradle/wrapper/dists里。比如 Windows 是C:\Users\你的用户名\.gradle\wrapper\distsmacOS / Linux 是~/.gradle/wrapper/dists。如果这个目录被清理过Gradle 会重新下载如果目录权限不对Gradle 第一次写不进去可能也会反复尝试。我曾经遇到过一个同事项目在 D 盘他把用户目录挪到了网络共享路径上导致.gradle目录写入很慢每次构建都像在重新下载。后来把GRADLE_USER_HOME环境变量指到本地磁盘问题才消失。所以在折腾镜像之前先确认本机 Gradle 用户目录是否可写、空间是否足够这一点很多人会忽略。如果你是在 CI 容器里构建这个就更关键了。容器每次构建结束后文件系统如果没有持久化那么上次下载完的 Gradle 发行包不会保存在下一轮容器里。下一轮构建又得重新下载一遍。你看到 CI 日志总是停在Downloading ...不是代码有问题而是 CI 缓存策略没有把~/.gradle或指定GRADLE_USER_HOME目录保留下来。2.3 先判断是“卡住”还是“龟速下载”在改任何配置之前建议先确认网络链路是不是真的完全没流量。Windows 可以打开任务管理器看网络占用macOS 可以看活动监视器里的网络面板。如果当前进程一直在产生下行流量说明下载还在慢慢走只是速度很慢如果十几分钟几乎没有流量变化大概率是连接已经挂了但客户端还没触发超时。命令行下可以加--info参数看更多日志比如./gradlew --version --info--info会输出比较详细的连接和状态信息。如果日志里反复出现重试或者底层异常信息被吞掉了你还可以直接看 Gradle 用户目录下的日志文件。遇到这种长时间无进展的情况不要一直干等直接按下一章的镜像方案处理几分钟就能把下载源换成国内速度更友好的地址。3. 最实用的解法把 distributionUrl 换成国内镜像3.1 找到并修改 gradle-wrapper.properties这是最常见、也最推荐的第一种解法。先找到项目里的gradle/wrapper/gradle-wrapper.properties注意不是build.gradle也不是 Gradle 安装目录里的配置。一个原生 Android 项目的路径通常是android/gradle/wrapper/gradle-wrapper.properties如果是 Flutter 项目就在android/gradle/wrapper/下React Native 项目类似一般也是android/gradle/wrapper/。如果项目是纯 Kotlin / Java 项目会在项目根目录的gradle/wrapper/下。打开后内容类似这样distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://services.gradle.org/distributions/gradle-7.6-all.zip zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/dists把distributionUrl一行替换成腾讯云镜像地址distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-7.6-all.zip或者华为云镜像地址distributionUrlhttps\://mirrors.huaweicloud.com/gradle/gradle-7.6-all.zip这里保留https\://这种写法没有问题。因为在 Java Properties 文件里反斜杠转义冒号后最终解析出来仍然是https://这是 Gradle 官方配置文件里最常见的写法。如果你改成不带反斜杠的普通 URL很多情况下也能识别但为了跟原始文件风格一致我还是建议保留。如果你判断当前项目用不到 Gradle 源码可以顺手把文件名改成bin版本进一步减小下载体积distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-7.6-bin.zip改之前先停掉项目相关的 Gradle 进程不要一边跑构建一边改配置文件否则修改可能不会生效甚至会因为文件被占用而保存失败。3.2 验证镜像地址和清理本地旧缓存修改完distributionUrl后如果之前因为官方源下载失败而留下了残缺缓存最好把对应的缓存目录清理掉。旧缓存的位置在~/.gradle/wrapper/dists/gradle-7.6-all/Windows 上执行Remove-Item -Recurse -Force $env:USERPROFILE\.gradle\wrapper\dists\gradle-7.6-*macOS / Linux 上执行rm -rf ~/.gradle/wrapper/dists/gradle-7.6-*如果你只改了 all 到 bin那么旧缓存目录可能叫gradle-7.6-all如果改成了gradle-7.6-bin记得把入口 URL 里对应版本号改一致再清理。接着在项目根目录重新执行./gradlew --version正常的话会看到从腾讯云或华为云镜像下载的新进度条下载速度通常比官方源稳定很多。Android Studio 用户在执行完命令行验证后打开项目并选择File Sync Project with Gradle Files让 IDE 也重新同步一遍。有一个坑需要提醒镜像源是直接把官方发行包同步到自己的对象存储里文件名和目录结构和官方大体保持一致。但如果你用了非常旧或非常特别的 Gradle 版本某些镜像不一定保留了所有历史版本可能在访问时返回 404。建议先打开镜像目录页确认存在对应版本再换地址。3.3 团队项目中要不要改 wrapper 文件在团队项目里修改gradle-wrapper.properties是一件影响所有人的事不能只考虑本机下载速度。比如你把地址换成某个镜像而团队其他成员所在网络访问这个镜像也很慢那他们同样会被卡住。所以比较稳妥的做法是先确认你们团队都更倾向哪个镜像或者你们内部是不是有统一软件源。如果是个人项目或者团队规模不大直接把镜像 URL 提交到仓库里问题不大。现在很多国内开源项目的 README 里也经常建议把 Wrapper 的发行包源换成镜像。只要你们用同一个容器环境或同一类网络统一换掉会比一两个人手动改更好维护。但不要把只在本机有效的路径提交到仓库。例如你手动把 zip 放在D:/tools/gradle-7.6-all.zip然后把distributionUrl写成本地file:///地址提交后同事拉下来根本无法从这个路径下载。这种本地方案适合临时解决个人环境问题提交代码前要记得改回通用镜像地址。另外如果你们的 CI 构建服务器在国内也请在 CI 侧的代码库里保持同一个镜像地址。CI 机器第一次构建时也要经历同样的下载过程不改的话超时风险一样存在。3.4 如果配置文件里有 distributionSha256Sum部分项目的gradle-wrapper.properties里除了基础字段还会额外配置一条distributionSha256Sum用来校验下载到的 zip 包哈希防止文件被篡改或下载不完整。换了镜像源后理论上官方发行包在镜像端是一致的话哈希值不会变所以校验可以通过。不过镜像同步偶尔会有延迟或者你手动把 all 改成 bin 之后哈希值肯定和原来不一样此时 Wrapper 会提示Verification of Gradle distribution failed解决方式很简单要么找到对应新文件的 SHA-256 值并更新distributionSha256Sum要么在本地环境先把这一行删掉。要在团队环境里保留校验的话建议下载完实际文件后用shasum -a 256 gradle-7.6-all.zip或certutil -hashfile计算你拿到的文件哈希再写到配置里。这样既保留安全性也不会卡在这一步。4. 网络不行时兜底手动下载和离线缓存方案4.1 用 file:// 分布 URL 让 Wrapper 本地安装如果你所在网络的对外下载实在不稳定或者镜像站也经常断可以直接把 zip 下载下来然后用 Gradle Wrapper 的本地文件 URL 机制安装。先去腾讯云或华为云镜像的网页里找到gradle-7.6-all.zip用浏览器拖到本地下载或者用curl下载到固定目录。假设下载到 Windows 上的D:\tools\gradle-7.6-all.zip你可以临时把distributionUrl改成distributionUrlfile\:///D:/tools/gradle-7.6-all.zipmacOS / Linux 上如果 zip 放在/opt/gradle/gradle-7.6-all.zip可以写成distributionUrlfile\:///opt/gradle/gradle-7.6-all.zip执行./gradlew --version后Gradle 会认为发行包已经“下载”完成从本地文件解压到 Wrapper 缓存目录里。整个流程不再访问外网速度非常快。等本地缓存建立后如果项目里已经提交了正常镜像地址你可以把distributionUrl改回来下次构建时因为缓存里已经有对应版本的发行包就不会再去下载。一定要记住这种本地路径方案只适合个人临时处理不适合直接提交到版本库。不同人的操作系统路径完全不同提交到仓库后反而会给别人制造新的下载异常。4.2 把发行包放到公司内部文件服务如果你是团队的技术负责人或 DevOps还有一种更适合常态化的做法把 Gradle 发行包统一放到公司内网可达的文件服务或对象存储上团队的distributionUrl直接指向内网地址。比如distributionUrlhttps\://gradle.internal.example.com/dist/gradle-7.6-all.zip只要是项目成员能够访问的内网 HTTP/HTTPS 地址Gradle Wrapper 都能正常处理。这样首次下载走内网速度快得多你甚至可以把多次验证过的版本和校验和一起维护好内部统一发布。如果不想搭内网下载服务也可以考虑在公司内部的 Maven 私服或制品仓库里建一个原始静态资源目录把 zip 传上去。关键是让所有开发者和 CI 用同一个 URL避免私人本地路径和公共 URL 混乱。对于无法联网的离线机器还有一个更原始但直观的方式直接把上一台机器~/.gradle/wrapper/dists目录里的对应文件夹整体拷贝到离线机器的相同位置。前提是两台机器的用户目录路径要一致或者你通过设置GRADLE_USER_HOME统一指定目录。这个方法很多实施文档里没写但在内网离线环境下非常管用。4.3 使用本机 Gradle 绕过 Wrapper 的做法与坑有些人会想与其下载 Wrapper 指定的版本不如给机器装一个全局 Gradle然后用全局gradle命令执行构建这样不就不用下载了吗这个想法有一定道理但它在项目里并不解决核心问题。只要你执行./gradlewWrapper 检查到缓存没有对应版本时还是会去下载而大多数项目的构建命令和 IDE 自动调用都倾向于使用 Wrapper。因为你改了distributionUrl但全局 Gradle 版本不一样打包行为也可能有差异。如果真想完全绕开 Wrapper可以临时使用gradle命令而不是gradlew命令。比如安装一个和项目要求一致的 Gradle 7.6 到系统里然后直接运行gradle assembleDebug。不过推荐只在应急时这么做因为团队和 CI 仍然以 Wrapper 为准你本机用全局版本可能会掩盖一些只在仓库 Wrapper 配置下出现的问题。如果项目代码里使用了 Gradle Wrapper 生成器你可以通过全局 Gradle 重新生成 wrapper 文件gradle wrapper --gradle-version 7.6这个命令重新生成gradlew和gradle/wrapper/gradle-wrapper.properties但它只是把版本信息写进去并不会把你的全局安装包直接复制到项目里。最终其他机器执行./gradlew时该下载还是会下载。所以别把它当免下载方案。5. 高频报错、连带问题和我的排查顺序5.1 常见错误信息速查表下面这些是我在实际项目里遇到比较多的 Gradle 发行包下载相关问题做成速查表方便你直接对照。现象直接原因解决方向卡在Downloading https://services.gradle.org/...官方地址连接受限或下载慢换成腾讯云或华为云镜像报java.net.SocketTimeoutException: connect timed out建立 TCP 连接超时检查curl -I换镜像地址报java.net.SocketException: Connection reset下载过程中连接被重置换稳定镜像或手动下载后再安装提示Could not HEAD ...Wrapper 获取远端信息失败确认网络能否访问该 URL检查项目配置提示Verification of Gradle distribution failed配置的 SHA-256 不对更新校验和或临时移除该行明明改了镜像地址还是从原地址下载改错了项目 / 缓存未清理找出实际使用的 wrapper 文件清理旧缓存目录每次构建都重新下载缓存目录不可写或 CI 无缓存持久化设置GRADLE_USER_HOMECI 增加缓存下载完解压时报权限错误.gradle目录权限不足修复目录权限或用本地用户目录这些错误看着吓人其实底层就两类下载源不可达或下载过程中断以及本地缓存/权限异常。先根据表格锁定大致方向再动手修改配置比盲目重装工具高效得多。5.2 Gradle 版本与 JDK 不兼容和下载问题同时出现搜索热度里有一句话是 “The projects Gradle version 6.7.1 is incompatible with the Gradle JVM version”。这类提示也经常在解决完下载问题后出现因为刚才还在纠结能不能把 Gradle 下载下来下载完了又发现当前 IDE 或 JAVA_HOME 指向的 JDK 版本和 Gradle 不兼容。Gradle 每个版本对运行它的 JVM 版本都有支持范围。通常 Gradle 7.6 可以运行在主流的 JDK 11、17 上如果 Android Studio 的 Gradle JDK 设置成了 JDK 21而项目 Gradle 版本较老就可能在启动阶段直接报不兼容。解决方式不是重装 Gradle而是把构建工具链里的 JVM 版本调一致。Android Studio 里可以打开Settings Build Tools Gradle查看Gradle JDK设置命令行构建则确认JAVA_HOME指向正确的 JDK。如果项目的 Gradle 版本必须维持 7.6最好把相关 JDK 切到 17如果项目允许升级 Gradle再考虑升级到支持新 JDK 的版本。这个顺序一定不要反否则你会陷入一边调下载、一边调编译环境的泥潭。5.3 Flutter 项目里的特殊提示Flutter 项目同样使用 Gradle Wrapper 构建 Android 端配置文件位置比较隐蔽经常有人找错。Flutter 项目的 Android 目录下才有 Gradle 相关配置路径是你的Flutter项目/android/gradle/wrapper/gradle-wrapper.properties有时升级 Flutter 或更换模板后控制台会出现类似 “You are applying Flutters main Gradle plugin imperatively using the apply script” 的提示。这句话是在告诉你要改变 Flutter Gradle 插件的应用方式它和当前Downloading卡住不是同一个问题。遇到时先保持冷静先解决下载源问题再处理构建脚本插件的迁移不要在一次操作里同时改太多内容否则很难判断是谁导致的。如果你的 Flutter 项目是多人协作建议把gradle-wrapper.properties的改动单独提一次提交把 Flutter 插件迁移的改动拆到另一次提交这样出现问题后可以快速回滚排查。5.4 我的从零到跑通排查顺序最后分享一下我面对这个问题的标准操作顺序。先说结论绝大多数情况在 5 分钟内能恢复正常真正需要手动下载的是极少数。第一步先停掉当前构建./gradlew --stop第二步确认官方地址通不通curl -I https://services.gradle.org/distributions/gradle-7.6-all.zip如果不通直接准备换镜像。第三步打开 wrapper 配置文件把distributionUrl换成腾讯云或华为云镜像地址并将文件名改成bin以减小体积。第四步清理旧缓存目录。第五步回到项目根目录执行./gradlew --version看到下载进度和版本号后再执行一次你原本要做的构建命令比如./gradlew assembleDebug或 Android Studio 同步。如果镜像下载还是失败我会看一下是不是下载过程中连接中断然后再手动用浏览器或下载工具把 zip 拉下来配合file:///临时地址安装。安装完成后改回镜像地址保证项目后续可复现。我在实际项目里踩过不少次“执着于官方源”的坑。早期我以为只要多等一会总会成功结果一次 CI 构建在下载阶段反反复复耗了半个小时。后来把 Wrapper 的下载地址统一换到镜像并把 all 改成 bin整个首次构建时间缩短了非常明显。最后再提醒一句修好本机下载问题后记得看下项目里的gradle-wrapper.properties要不要提交更新。如果你是团队里唯一被下载问题卡住的人可以先只在本地改不污染公共配置如果大家都有同类问题就统一改成团队认可的镜像地址再提交到仓库。这个下载问题本身不复杂怕的是在错误的方向上重试太多次越等越焦虑。