ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Gradle构建加速全攻略:从init.gradle到离线包的镜像配置实践

Gradle构建加速全攻略:从init.gradle到离线包的镜像配置实践 先聊聊我自己的实际经历吧。前两年带一个移动端团队接了个大活几十个模块的安卓工程一到新同事入职拉代码光Gradle环境就得折腾一个下午。最常见的报错就是那句让人血压飙升的could not install gradle distribution from ... reason: java.net.sockettimeoutexc甚至有的小伙伴直接在群里喊“电脑是不是坏了”。其实真的不是电脑坏了百分之九十的情况是默认下载地址在跟我们这边的网络环境闹别扭。Gradle官方发行版和Maven中央仓库的服务器都在海外直接访问时丢包、超时太常见了。这不是代码问题也不是你电脑配置问题而是“拉包”这条网络链路不稳。这篇文章我就把自己给团队和项目配置国内镜像的完整思路记录下来从依赖仓库到Wrapper发行版再到现在最头疼的离线包和Jenkins联动一次性讲明白。1. Gradle 镜像到底在解决什么问题1.1 核心痛点网络延迟与构建超时很多初学者会把Gradle当成一个跟Maven同类的“依赖包管理工具”其实Gradle本质上是一个“构建工具”它管理依赖的能力只是它的一部分功能。Gradle在构建时会经历两步跟网络强相关的操作第一步是根据gradle-wrapper.properties里的distributionUrl下载整个Gradle工具包第二步才是根据项目里的依赖声明去Maven仓库下载开发包。问题往往就出在这两步上。默认的distributionUrl指向Gradle官方服务器默认的依赖仓库指向repo1.maven.org和dl.google.com。这几个域名在我们国内网络的访问速度非常不稳定经常出现TCP握手成功但数据包迟迟不回来最终抛出SocketTimeoutException的情况。之前在没配置镜像的时候我甚至遇到过Gradle一个几十MB的zip包断断续续下载了三个多小时最后校验失败直接前功尽弃。1.2 Gradle 发行版镜像与依赖仓库镜像的区别这里必须区分清楚两个完全不同的概念发行版镜像和依赖仓库镜像。发行版镜像负责提供Gradle这个构建工具本身的zip压缩包。比如你写代码用的distributionUrl下载的是gradle-8.7-bin.zip这个zip包解压后就是Gradle的完整安装环境。依赖仓库镜像负责提供构建时需要的第三方库jar包比如Spring Boot依赖、AndroidX包、Glide图片框架等。Gradle通过repositories配置去查找这些包。区分不清的话一定会踩坑。比如你在build.gradle里把腾讯云镜像配得再完美也解决不了Wrapper下载超时的问题因为那是发行版的活必须去改distributionUrl。反过来也一样你就算把Gradle发行版换成了本地离线包构建时依赖包下不动依然会卡在Could not resolve all dependencies for configuration这种编译错误上。2. 全局配置指南初始化脚本 (init.gradle) 的实战用法2.1 为什么优先推荐 init.gradle 统一管控很多新人在网上搜镜像配置搜到的答案五花八门最常见的教学是让你在项目里的build.gradle文件加repositories代码块。这么做倒也没错但有个明显的弊端团队里几十个微服务项目每个项目的build.gradle都要去手动改一遍漏掉一个项目就等着构建失败吧。更推荐的正确姿势是使用init.gradle脚本。这个文件位于用户目录/.gradle/init.gradle下Gradle在启动时会自动读取该脚本相当于给这台机器上的所有Gradle项目都注入一套全局的仓库配置。只要运维或者团队技术负责人把这份文件分发到每个人电脑上所有项目的依赖下载都会自动走镜像仓库一劳永逸项目代码不需要做任何修改。2.2 配置阿里云 / 腾讯云镜像仓库含代码示例要更新入门直接复制下面这段内容保存到C:\Users\你的用户名\.gradle\init.gradle或者~/.gradle/init.gradle下注意是.gradle目录不是gradle。allprojects { repositories { maven { name aliyun-public url https://maven.aliyun.com/repository/public } maven { name aliyun-google url https://maven.aliyun.com/repository/google } maven { name aliyun-gradle-plugin url https://maven.aliyun.com/repository/gradle-plugin } maven { name tencent url https://mirrors.cloud.tencent.com/nexus/repository/maven-public } mavenCentral() } }这里为什么要写成allprojects而不是直接写repositories因为在现代Gradle7.x及以上里依赖仓库配置有两个作用域一个是settings.gradle里的dependencyResolutionManagement另一个是模块级的build.gradle。如果不写allprojects会导致子模块的仓库配置没有生效。另外我习惯把阿里云和腾讯云的源都加上阿里云主打稳定腾讯云作为兜底万一某个源拉取失败Gradle会自动去下一个仓库源里找。2.3 按项目配置 build.gradle 的备用方案有一种情况不适合用init.gradle那就是你开发的是开源项目需要把自己的依赖配置写清楚方便别人直接fork后能跑起来。这时候就需要在项目里显式声明仓库地址。在项目根目录的settings.gradle文件里找到dependencyResolutionManagement代码块加入以下配置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 } mavenCentral() } }配置好之后可以在命令行执行gradle build --refresh-dependencies看下实际下载速度如果日志里出现Could not GET https://maven.aliyun.com/...这种报错大概率是阿里云那个源里没有对应的依赖包需要检查依赖坐标是否写错。3. Gradle Wrapper 发行版下载加速不能只配仓库3.1 Wrapper 超时的完整排查思路Gridle项目的根目录会有一个gradle/wrapper/gradle-wrapper.properties文件这个文件里定义了Gradle的具体版本号和下载地址。当你执行./gradlew build命令时Gradle Wrapper会根据这个文件去下载对应版本的Gradle发行版。前面提到的could not install gradle distribution from ... reason: java.net.sockettimeoutexc就是在这里触发的。排查流程一般分三步骤检查distributionUrl指向的地址如果还是官方域名services.gradle.org那基本妥了国内网络环境大概率会超时。检查网络代理这里的检查不是让大家用什么代理工具而是检查系统里是否配置了HTTP代理。某些公司内网会强制设置代理如果代理配置错误Gradle会尝试通过代理连接同样导致超时。检查防火墙极少见情况本机防火墙拦截了Java进程的对外网访问权限。3.2 手把手修改 gradle-wrapper.properties 替换国内镜像直接编辑项目根目录下gradle/wrapper/gradle-wrapper.properties文件把distributionUrl地址替换成国内可访问的镜像distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-8.7-bin.zip networkTimeout10000 validateDistributionUrltrue zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/dists注意地址里的https\://这个反斜杠是转义字符写的时候不能漏否则会识别成注释。腾讯云镜像支持gradle-7.6.1-bin.zip、gradle-8.7-bin.zip等主流版本理论上你说一个版本只要不算远古版本它都能从华为云或腾讯云找到。如果团队还在用旧版本gradle-4.x建议升级或者去Gradle官方GitHub仓库手动下载对应版本的zip包放到本地指定目录下一节细讲。这里的networkTimeout10000参数也值得一提。默认值是0或者不设置表示无限等待一旦断网就可能卡住整个构建。设置为10000毫秒即10秒超时如果镜像源也连不上Gradle能提早报错出来方便排查。3.3 应对版本校验Gradle 校验和验证失败问题改完源之后很多同学会遇到以下报错Verifying the distribution sha-256 checksum ... Checksum mismatch for distribution...这是因为Gradle在下载完发行版之后会校验SHA-256值。官方镜像和国内镜像提供的包虽然名字相同但有可能因为压缩包压缩时间戳不一致导致校验和与官方注册的值不一致。Gradle默认会拒绝使用校验和不一致的包。解决办法有两种。第一种在gradle-wrapper.properties里注释或去掉distributionSha256Sum字段让Gradle跳过校验。但这样做存在理论上的安全隐患不建议在生产环境长期使用。第二种去镜像站找到该版本的.sha256文件把正确的摘要值填到distributionSha256Sum字段。比如distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-8.7-bin.zip distributionSha256Sum9d7adf4d1eb4c5a7f...具体值以镜像站校验文件为准如果嫌麻烦最简单的做法是把distributionSha256Sum这个字段整个删掉Gradle会对未设置校验和的情况采用不同的校验策略只要zip包能正常解压新旧版本的兼容性校验就能通过。4. 常见开发场景的镜像配置联动4.1 Android Studio / IDEA 本地 Gradle 安装与镜像关联在IntelliJ IDEA或Android Studio中不管是创建新项目还是导入旧项目IDE都会尝试通过内置的Gradle路径下载版本。如果你看到IDE底部进度条一直卡在“Downloading Gradle distribution”不动那很可能就是走了默认官方源。IDEA里可以手动指定本地Gradle路径依次打开File - Settings - Build, Execution, Deployment - Build Tools - Gradle在“Gradle distributions”下拉框中选择“Local installation directory”然后指定你刚才通过镜像下载解压好的Gradle目录比如D:\software\gradle-8.7。这样IDEA就不会去下载发行版直接使用本地磁盘的Gradle构建速度提升极其明显。4.2 Jenkins 自动化构建的加速手段编译机配置技巧在CI/CD环境里Jenkins机器通常是云端一次性编译机如果每次构建都去官方源拉Gradle必然导致流水线超时。比较好的做法是两步走第一步给Jenkins机器配置好~/.gradle/init.gradle镜像这一步能解决依赖jar下载问题。第二步由于Gradle发行版体积较大建议在流水线脚本里提前把Gradle安装好通过GRADLE_USER_HOME环境变量指向一个包含解压后Gradle的公共目录或者直接使用gradle wrapper --gradle-version 8.7配合镜像源让Wrapper快速下载。另外特别提醒一下Jenkins自身的插件升级。Jenkins的升级站点默认是updates.jenkins.io这个站点在国外同样存在极慢的问题建议在Manage Jenkins - Manage Plugins - Advanced里把升级站点URL改成清华大学的镜像https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json。这一行配置能解决Jenkins插件装不上的坑和Gradle镜像构成一套“内外兼修”的组合拳。4.3 Flutter 项目特有的 Gradle 配置报错梳理Flutter项目底层依赖Gradle来编译Android部分但Flutter工具链生成的Gradle工程结构和原生Android工程略有不同有个高频报错特别容易让新手懵圈You are applying Flutters main Gradle plugin imperatively using the apply script method, which is no longer supported...这个报错并不是镜像或网络导致的而是Flutter SDK版本与项目里的Gradle版本不匹配导致的大概率是你的Flutter版本升级了但项目里android/settings.gradle或android/build.gradle还是老的插件声明方式。解决办法是将老的apply plugin: com.android.application改成新式的插件管理在根目录settings.gradle里声明plugins { id dev.flutter.flutter-plugin-loader version 1.0.0 id com.android.application version 7.3.0 apply false }如果你排查完发现报错依旧可以用flutter clean清掉旧的构建缓存再重新执行flutter pub get。这个报错和镜像无关但排查顺序建议放在镜像配置之后避免把网络问题跟工程配置问题混在一起。具体的Flutter版本对应关系可以查看Flutter官方文档但核心就是这么一句Flutter升级后Android侧的构建文件结构也要跟着变。5. 离线包方案与团队内网分发实战5.1 如何下载并配置 Gradle 离线包如果公司网络严格限制外网访问或者团队有十几台编译机都依赖同一套Gradle最稳妥的方案是离线包预置。在能访问外网的机器上用浏览器直接访问腾讯云镜像地址下载gradle-8.7-bin.zip解压到一个公共目录比如C:\gradle或/opt/gradle。然后把根目录下的bin目录加进系统环境变量PATH这样命令行里直接敲gradle -v就能看到版本信息。对于Wrapper项目直接把压缩包放进GRADLE_USER_HOME/wrapper/dists/gradle-8.7-bin/对应的哈希文件夹里注意文件夹名带哈希值是Gradle根据URL自动生成的不同机器的哈希可能不一样更推荐的方式是让第一台机器通过镜像下载成功后直接共享整个GRADLE_USER_HOME目录给其他机器。5.2 私有镜像 / 本地缓存策略避免团队内重复下载小团队可能觉得离线包已经够用了但到几十人的研发团队不同项目不同版本每个版本再让运维去手动下载分发就非常低效。这时候可以在内网搭一个简单的软件源服务比如用Nginx做静态文件服务直接把Gradle发行版存放对应的目录结构对于Maven依赖推荐用Nexus或Artifactory这类私服仓库运维配置好之后所有开发者的init.gradle都指向内网Nexus地址。我之前的经验是Nexus配置不需要太复杂建立一个maven-public仓库组里面聚合maven-central、jcenter、google三个远程源设置“远程仓库访问URL”让Nexus自动从阿里云同步。开发者只需要在init.gradle里写一行地址allprojects { repositories { maven { url http://192.168.1.100:8081/repository/maven-public/ } } }这样做有几个额外好处第一依赖包一旦被Nexus缓存第二次构建直接从内网硬盘读取网络耗时理论上接近0第二即使外网源哪天临时故障内网Nexus的缓存依然能保证构建不中断第三可以对团队使用的依赖做统一版本管控避免有人偷偷引入存在漏洞的旧版本。5.3 实操经验总结我的一些避坑参考配置镜像这事看起来简单但真正遇到问题时细节往往决定成败。以下几条是我在这些年踩坑踩出来的经验写在这里供大家参考。第一不要多个镜像地址混用在同一仓库组里。我曾试过把阿里云、腾讯云、华为云全塞进一个repositories本意是增加冗余实际会导致依赖解析时从一个源找不到Gradle就会去另一个源反复尝试构建时间反而翻倍而且还可能导致依赖版本冲突。建议就选一个稳定源作为主镜像另一个作为备用不要贪多。第二优先保持Gradle版本统一。团队里一旦出现gradle-7.6、gradle-8.5、gradle-8.7多个版本乱飞的景象镜像配置再完善也没用因为每个版本的发行包都接近100MB每次切换版本都要重新下载。我用过一个办法在项目根目录写一个gradle.properties把版本号和仓库地址统一写进去通过脚本自动化生成wrapper配置谁要升级版本改一个环境变量即可。第三关于“代理”这件事要正确理解。点击gradle 下载代理地址这个热词进来的朋友注意不要把这里的代理理解成某些特殊工具。真正靠谱的做法是让运维配好Nexus私服或者内网HTTP代理网关设置好systemProp.http.proxyHost/systemProp.http.proxyPort这样Gradle下载走企业内部网络出口既安全又合规。我在生产环境见过因为私自使用代理工具导致证书校验失败、构建产物异常的问题严重影响上线因小失大。第四如果Gradle构建一直卡在某个依赖的解析上别死磕网络先看代码。有次团队开发遇到Could not resolve org.springframework.boot:spring-boot-starter-parent:2.7.18大家以为是镜像问题排查了半天最后发现是某个同事在build.gradle里把版本号2.7.18手误打成了2.7.180。镜像只是加速工具不是万能的报错时第一件事永远应该是看完整错误日志再用gradle dependencies --debug定位具体是哪个坐标失败。第五记得清理缓存。有时候改完init.gradleGradle还会优先命中本地缓存导致明明新配置生效了却没按预期走。执行构建环境太极端时直接删掉~/.gradle/caches和~/.gradle/wrapper/dists下的对应目录能让Gradle老老实实走一遍新配置。当然清理缓存也有成本建议只在本地环境操作CI机器上不要动不动就清缓存。第六优先用gradle wrapper而不是系统全局Gradle命令。很多老手会图方便直接敲gradle build但如果你不小心升级了系统Gradle版本很可能导致构建行为与CI环境不一致。正确做法是提交gradlew和gradlew.bat脚本在CI和本地都用./gradlew build执行构建这样团队的环境完全统一烫手的问题就少了一大半。最后再分享一个实际收益数据吧。我负责的项目团队有20多名开发在接管Gradle网络问题之前新同事入职第一天基本都耗在处理依赖下载超时上效率极低。后来我花了半天时间搞定了init.gradle和腾讯云镜像顺手给CI机器做了Jenkins升级源和Nexus私服缓存从那以后新同事入职只需要复制一套.gradle目录基本十分钟就能把环境跑通构建速度也从原来平均十几分钟甚至更久稳定在了四分钟左右。这个投入产出比可以说是我做过最划算的一次环境治理之一了。
返回列表