news 2026/9/7 16:40:56

Gradle Wrapper下载卡死?从distributionUrl到国内镜像的彻底解决指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Gradle Wrapper下载卡死?从distributionUrl到国内镜像的彻底解决指南

最近在一个老项目上又碰见了这个折腾人的问题: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 目录,只有几个文件:gradlewgradlew.batgradle/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\dists,macOS / 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/下。

打开后内容类似这样:

distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists

distributionUrl一行替换成腾讯云镜像地址:

distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.6-all.zip

或者华为云镜像地址:

distributionUrl=https\://mirrors.huaweicloud.com/gradle/gradle-7.6-all.zip

这里保留https\://这种写法没有问题。因为在 Java Properties 文件里,反斜杠转义冒号后最终解析出来仍然是https://,这是 Gradle 官方配置文件里最常见的写法。如果你改成不带反斜杠的普通 URL,很多情况下也能识别,但为了跟原始文件风格一致,我还是建议保留。

如果你判断当前项目用不到 Gradle 源码,可以顺手把文件名改成bin版本,进一步减小下载体积:

distributionUrl=https\://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.zipcertutil -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改成:

distributionUrl=file\:///D:/tools/gradle-7.6-all.zip

macOS / Linux 上如果 zip 放在/opt/gradle/gradle-7.6-all.zip,可以写成:

distributionUrl=file\:///opt/gradle/gradle-7.6-all.zip

执行./gradlew --version后,Gradle 会认为发行包已经“下载”完成,从本地文件解压到 Wrapper 缓存目录里。整个流程不再访问外网,速度非常快。等本地缓存建立后,如果项目里已经提交了正常镜像地址,你可以把distributionUrl改回来;下次构建时因为缓存里已经有对应版本的发行包,就不会再去下载。

一定要记住:这种本地路径方案只适合个人临时处理,不适合直接提交到版本库。不同人的操作系统路径完全不同,提交到仓库后反而会给别人制造新的下载异常。

4.2 把发行包放到公司内部文件服务

如果你是团队的技术负责人或 DevOps,还有一种更适合常态化的做法:把 Gradle 发行包统一放到公司内网可达的文件服务或对象存储上,团队的distributionUrl直接指向内网地址。比如:

distributionUrl=https\://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命令执行构建,这样不就不用下载了吗?这个想法有一定道理,但它在项目里并不解决核心问题。只要你执行./gradlew,Wrapper 检查到缓存没有对应版本时,还是会去下载;而大多数项目的构建命令和 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

这个命令重新生成gradlewgradle/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_HOME,CI 增加缓存
下载完解压时报权限错误.gradle目录权限不足修复目录权限,或用本地用户目录

这些错误看着吓人,其实底层就两类:下载源不可达或下载过程中断,以及本地缓存/权限异常。先根据表格锁定大致方向,再动手修改配置,比盲目重装工具高效得多。

5.2 Gradle 版本与 JDK 不兼容:和下载问题同时出现

搜索热度里有一句话是 “The project's 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 Flutter's 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要不要提交更新。如果你是团队里唯一被下载问题卡住的人,可以先只在本地改,不污染公共配置;如果大家都有同类问题,就统一改成团队认可的镜像地址,再提交到仓库。这个下载问题本身不复杂,怕的是在错误的方向上重试太多次,越等越焦虑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 16:40:49

非科班转AI第3周,特征工程的坑逼着我重刷人工智能入门,精度从0.62跳到0.83

非科班转AI第3周,特征工程的坑逼着我重刷人工智能入门,精度从0.62跳到0.83 转行学人工智能的第22天,我坐在电脑前盯着 accuracy: 0.62 的结果发愣。这套房价预测项目我已经调了三次模型,从线性回归换到随机森林,超参调优也试过网格搜索,可验证集上的表现就是上不去。我翻回自己…

作者头像 李华
网站建设 2026/9/7 16:40:41

NSGA-II求解风光火储P2G需求响应多目标优化调度问题

做电力系统调度这些年&#xff0c;我最大的感受是&#xff1a;单一能源的“最优”&#xff0c;放到系统里往往就不是最优了。风电光伏出力一高&#xff0c;火电就得往低压&#xff0c;压完可能又面临爬坡跟不上&#xff1b;储能能搬电量&#xff0c;但容量有限&#xff0c;也不…

作者头像 李华
网站建设 2026/9/7 16:40:29

Buzz 离线转文字完全指南:本地 Whisper 语音识别新手教程

Buzz 离线转文字完全指南&#xff1a;本地 Whisper 语音识别新手教程 【免费下载链接】buzz Buzz transcribes and translates audio offline on your personal computer. Powered by OpenAIs Whisper. 项目地址: https://gitcode.com/GitHub_Trending/buz/buzz 对着半小…

作者头像 李华
网站建设 2026/9/7 16:39:07

AI上下文测量:从文本到群体效应的多层次模型实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 16:37:28

视频下载工具实测:浏览器嗅探原理与VidBrowser能力边界

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华