戰(zhàn):構(gòu)建工具安裝配置與避坑指南)
簡(jiǎn)介Gradle 6.5 完整發(fā)行包面向 Java/Android 開(kāi)發(fā)者與 Android Studio 用戶屬于離線構(gòu)建工具包尤其適合官方下載緩慢、網(wǎng)絡(luò)受限或需要統(tǒng)一構(gòu)建環(huán)境版本的項(xiàng)目團(tuán)隊(duì)。壓縮包約 139.01MB文件總數(shù)約 2000 個(gè)以 Java 源碼、HTML 文檔、Groovy/Kotlin 構(gòu)建腳本和 JAR 依賴庫(kù)為主并包含 bin、lib、docs、licenses、src 等標(biāo)準(zhǔn)目錄分別提供命令行入口、運(yùn)行庫(kù)、用戶文檔、許可信息和源碼資源解壓即可使用。該版本重點(diǎn)優(yōu)化了增量構(gòu)建緩存、依賴解析與 Android 插件兼容性同時(shí)提升 Gradle Wrapper 的傳輸安全能夠減少大型項(xiàng)目重復(fù)編譯耗時(shí)并降低構(gòu)建配置沖突風(fēng)險(xiǎn)。離線包可直接用于為項(xiàng)目搭建本地 Gradle 環(huán)境用于日常構(gòu)建、CI 集成或?qū)W習(xí) Gradle 6.5 內(nèi)部機(jī)制與插件 API避免從官方站點(diǎn)長(zhǎng)時(shí)間等待下載。已有 1059 人學(xué)習(xí)/瀏覽對(duì)于需要穩(wěn)定 Gradle 6.5 環(huán)境或排查構(gòu)建腳本的開(kāi)發(fā)者具有明確的參考價(jià)值。 看到gradle-6.5-all.zip這個(gè)文件名估計(jì)不少做過(guò) Java 構(gòu)建的老哥都眼熟。這不光是一個(gè)普通的壓縮包它背后是 Gradle 構(gòu)建工具在 2020 年年中的一個(gè)重要發(fā)行版本。到今天我仍然會(huì)在不少遺留項(xiàng)目里碰到它尤其是那些鎖定了 Gradle Wrapper 版本的老系統(tǒng)。這個(gè) zip 包代表的意義很直接一份完整、離線可用、開(kāi)箱即用的構(gòu)建工具發(fā)行包。這篇文章不打算給你念官方文檔而是從一個(gè)實(shí)際用它跑過(guò)項(xiàng)目的開(kāi)發(fā)者角度把這個(gè)文件拆解開(kāi)它是什么、為什么用 all 版本、裝上之后怎么配、最常見(jiàn)的問(wèn)題出在哪、以及到底該不該從 6.5 往上升。內(nèi)容涉及安裝、配置、構(gòu)建腳本、問(wèn)題排查和版本選擇適合剛接觸 Gradle 的新手也適合被舊項(xiàng)目綁住手腳想系統(tǒng)梳理一遍的老手。1. 拆開(kāi)標(biāo)題看門道gradle-6.5-all.zip 到底是個(gè)什么東西1.1 Gradle 在構(gòu)建工具里是什么定位Gradle 是一個(gè)自動(dòng)化構(gòu)建工具主要服務(wù)于 JVM 生態(tài)但通過(guò)插件也能構(gòu)建 C、Python、前端工程。它的核心優(yōu)勢(shì)在于基于有向無(wú)環(huán)圖的任務(wù)編排以及增量構(gòu)建能力——不是每次把所有東西重新編譯一遍而是只重做發(fā)生變化的部分。這一點(diǎn)和早期 Maven 的全量構(gòu)建思路有明顯差異也是很多人從 Maven 遷移過(guò)來(lái)的直接原因。gradle-6.5-all.zip就是 Gradle 6.5 版本的完整發(fā)行包壓縮格式是 zip。它是跨平臺(tái)的Windows、macOS、Linux 都能用同一份文件。下載之后解壓到本地目錄配置好環(huán)境變量就能在命令行里跑gradle命令。項(xiàng)目里的構(gòu)建腳本默認(rèn)叫build.gradleGroovy DSL或build.gradle.ktsKotlin DSLGradle 會(huì)讀取并執(zhí)行里面的任務(wù)定義。1.2 all 版本和 bin 版本有什么區(qū)別Gradle 官方在 GitHub Releases 上會(huì)同時(shí)發(fā)布兩種 zip包名內(nèi)容適用場(chǎng)景gradle-6.5-bin.zip僅包含 Gradle 運(yùn)行所需的二進(jìn)制文件日常構(gòu)建體積小夠用gradle-6.5-all.zip二進(jìn)制文件 源碼 完整文檔想讀源碼、離線看文檔、研究?jī)?nèi)部實(shí)現(xiàn)從實(shí)際使用角度絕大多數(shù)項(xiàng)目用 bin 版本就夠了。all 版本多出來(lái)的主要是src目錄下的 Gradle 源碼和docs目錄下的用戶手冊(cè)、DSL 參考。如果你需要離線環(huán)境查閱文檔或者排查某個(gè) Task 內(nèi)部實(shí)現(xiàn)邏輯all 版本會(huì)很方便如果只是跑構(gòu)建bin 版本更省空間。我個(gè)人的習(xí)慣是個(gè)人開(kāi)發(fā)機(jī)裝 all 版本因?yàn)榕紶栆幌略创aCI 服務(wù)器用 bin 版本追求速度和干凈。1.3 6.5 這個(gè)版本號(hào)為什么值得單獨(dú)拿出來(lái)說(shuō)Gradle 6.5 發(fā)布于 2020 年 6 月是一個(gè)功能相對(duì)穩(wěn)定的版本。它引入了配置文件緩存早期版本、文件系統(tǒng)監(jiān)聽(tīng)File System Watching的改進(jìn)并且完善了對(duì) Java 14 的支持。在 6.x 系列里6.5 屬于中期版本既沒(méi)有 6.0 剛大改時(shí)的激進(jìn)也沒(méi)有 6.8 之后引入大量新特性時(shí)的復(fù)雜度。更重要的是很多國(guó)內(nèi)技術(shù)博客、開(kāi)源項(xiàng)目、教學(xué)視頻在 2020-2021 年都基于 Gradle 6.5 寫的示例。你在搜索引擎里搜Gradle 配置大概率會(huì)看到基于 6.x 的答案。所以哪怕現(xiàn)在 Gradle 已經(jīng)出了 8.x6.5 依然是存量代碼里的一塊基石。2. Gradle 6.5 有哪些值得記住的能力2.1 文件系統(tǒng)監(jiān)聽(tīng)和增量構(gòu)建Gradle 6.5 對(duì)文件系統(tǒng)監(jiān)聽(tīng)的實(shí)現(xiàn)比之前版本成熟了不少。它會(huì)在后臺(tái)監(jiān)聽(tīng)項(xiàng)目目錄里文件的變化而不是每次構(gòu)建都全量掃描文件系統(tǒng)。對(duì)于大型多模塊項(xiàng)目這個(gè)改進(jìn)能顯著縮短無(wú)變化時(shí)的構(gòu)建時(shí)間。不過(guò)要注意文件系統(tǒng)監(jiān)聽(tīng)在 Windows 上和某些網(wǎng)絡(luò)驅(qū)動(dòng)器上偶爾會(huì)失效這時(shí) Gradle 會(huì)自動(dòng)退化為普通模式構(gòu)建速度會(huì)慢一些。如果發(fā)現(xiàn)構(gòu)建異常慢可以看看~/.gradle/gradle.properties里是否有關(guān)閉監(jiān)聽(tīng)的相關(guān)配置比如org.gradle.vfs.watchfalse。2.2 Java 版本支持策略6.5 支持運(yùn)行在 Java 8 到 Java 14 上同時(shí)可以用toolchain工具鏈機(jī)制構(gòu)建更高版本的 Java 項(xiàng)目。這個(gè)機(jī)制很關(guān)鍵即使你的開(kāi)發(fā)機(jī)裝的是 JDK 11也可以通過(guò)配置工具鏈讓 Gradle 自動(dòng)下載 JDK 15 來(lái)編譯指定模塊。java { toolchain { languageVersion JavaLanguageVersion.of(11) } }這一段配置在 6.5 里已經(jīng)可用但完整的多平臺(tái)工具鏈檢測(cè)是后面幾個(gè)版本才成熟的。如果你在 6.5 上用工具鏈遇到無(wú)法自動(dòng)下載 JDK的情況多半是 Foojay Toolchains 插件還沒(méi)適配需要手動(dòng)指定路徑。2.3 構(gòu)建緩存和依賴緩存的設(shè)計(jì)Gradle 的構(gòu)建緩存是分兩層的本地緩存和遠(yuǎn)程緩存。本地緩存在~/.gradle/caches目錄遠(yuǎn)程緩存可以通過(guò)配置buildcache指向一個(gè) HTTP 服務(wù)比如 Jenkins 的 Gradle Cache 插件或者 Artifactory。6.5 的本地緩存默認(rèn)開(kāi)啟它對(duì)依賴 Jar 包和構(gòu)建產(chǎn)物分別管理。這里有個(gè)常見(jiàn)坑依賴緩存損壞。如果你強(qiáng)行中斷 Gradle 進(jìn)程~/.gradle/caches/modules-2下可能出現(xiàn)損壞文件后續(xù)構(gòu)建會(huì)一直報(bào) Could not resolve 之類的錯(cuò)誤。解決辦法是刪掉modules-2目錄重新下載不要一個(gè)一個(gè)手動(dòng)刪。3. 從下載到跑通第一個(gè)構(gòu)建安裝配置全流程3.1 下載渠道與鏡像選擇最權(quán)威的地址是 Gradle 官方 GitHub Releases搜索gradle-6.5-all.zip就能找到。但大陸網(wǎng)絡(luò)環(huán)境下GitHub 下載速度經(jīng)常不理想。我建議優(yōu)先用國(guó)內(nèi)鏡像騰訊云鏡像https://mirrors.cloud.tencent.com/gradle/gradle-6.5-all.zip阿里云鏡像https://mirrors.aliyun.com/gradle/gradle-6.5-all.zip華為云鏡像https://mirrors.huaweicloud.com/gradle/gradle-6.5-all.zip這幾個(gè)鏡像的文件名和官方一致下載后可以對(duì)比 sha256 校驗(yàn)值。Gradle 官方在發(fā)布頁(yè)會(huì)給出 checksum用shasum -a 256 gradle-6.5-all.zip或者 Windows 下的certutil -hashfile gradle-6.5-all.zip SHA256來(lái)校驗(yàn)防止下載過(guò)程損壞。3.2 環(huán)境變量配置Windows、macOS、Linux以 Linux 為例假設(shè)我把 zip 解壓到了/opt/gradle-6.5sudo unzip gradle-6.5-all.zip -d /opt/ export GRADLE_HOME/opt/gradle-6.5 export PATH$GRADLE_HOME/bin:$PATH為了永久生效需要把這兩行寫入~/.bashrc或~/.zshrc。Windows 用戶在系統(tǒng)屬性里新建GRADLE_HOME環(huán)境變量指向解壓目錄再把%GRADLE_HOME%\bin加入Path。macOS 用戶還有一種更優(yōu)雅的方式用 Homebrew 安裝但 Homebrew 默認(rèn)版本可能不是 6.5。如果你確實(shí)要 6.5手動(dòng)解壓并配置GRADLE_HOME更可控。配置完成后終端里執(zhí)行g(shù)radle -v看到 Gradle 6.5 的版本信息和 JVM 信息就說(shuō)明裝好了。3.3 用 Wrapper 鎖定項(xiàng)目版本直接在命令行用全局 Gradle 有個(gè)問(wèn)題不同項(xiàng)目可能依賴不同版本的 Gradle全局版本無(wú)法兼顧。所以 Gradle 官方強(qiáng)烈推薦使用 Wrapper——也就是項(xiàng)目里的gradlew腳本和gradle/wrapper/gradle-wrapper.properties文件。一個(gè)典型的gradle-wrapper.properties內(nèi)容如下distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://services.gradle.org/distributions/gradle-6.5-all.zip zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/dists這里distributionUrl指定了 Gradle 6.5 all 版本。當(dāng)開(kāi)發(fā)者執(zhí)行./gradlew build時(shí)Wrapper 會(huì)自動(dòng)檢測(cè)本地是否存在對(duì)應(yīng)的發(fā)行包沒(méi)有就按 URL 下載。這里有一個(gè)關(guān)鍵優(yōu)化點(diǎn)把distributionUrl中的services.gradle.org換成國(guó)內(nèi)鏡像能大幅提升首次構(gòu)建速度。比如distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-6.5-all.zip改完后團(tuán)隊(duì)所有成員首次執(zhí)行g(shù)radlew都會(huì)從鏡像下載而不是緩慢的官方源。4. 實(shí)操項(xiàng)目里的配置與常用命令4.1 一個(gè)常規(guī) Java 項(xiàng)目的 build.gradle用 Gradle 6.5 構(gòu)建一個(gè) Java 項(xiàng)目最基礎(chǔ)的腳本長(zhǎng)這樣plugins { id java id application } group com.example version 1.0.0 repositories { maven { url https://maven.aliyun.com/repository/public } mavenCentral() } dependencies { implementation com.google.guava:guava:30.1-jre testImplementation org.junit.jupiter:junit-jupiter:5.7.0 } application { mainClass com.example.Main } test { useJUnitPlatform() }這里我刻意把repositories配成了阿里云鏡像優(yōu)先因?yàn)閲?guó)內(nèi)訪問(wèn) Maven Central 經(jīng)常超時(shí)。Gradle 6.5 的依賴解析支持implementation這種比compile更嚴(yán)格的配置減少不必要的依賴泄漏。4.2 多模塊項(xiàng)目的常用姿勢(shì)多模塊項(xiàng)目會(huì)在根目錄有一個(gè)settings.gradle文件rootProject.name my-app include core include web include admin每個(gè)子模塊有自己的build.gradle。在根目錄執(zhí)行./gradlew build時(shí)Gradle 會(huì)按照模塊間的依賴關(guān)系并行構(gòu)建。6.5 默認(rèn)支持并行構(gòu)建不過(guò)需要顯式開(kāi)啟org.gradle.paralleltrue如果不開(kāi)啟多模塊項(xiàng)目會(huì)按順序構(gòu)建耗時(shí)明顯增加。在新版本里并行構(gòu)建已經(jīng)是默認(rèn)策略但在 6.5 上需要自己配置。4.3 依賴管理與版本沖突Gradle 6.5 的依賴沖突策略和 Maven 不同它默認(rèn)選擇最高版本而不是最靠近根模塊的版本。這在某些情況下會(huì)引發(fā)意外。比如模塊 A 依賴lib:1.0模塊 B 依賴lib:2.0Gradle 會(huì)直接用 2.0。如果 A 在 2.0 下運(yùn)行有問(wèn)題需要手動(dòng)排除或者強(qiáng)制指定configurations.all { resolutionStrategy { force com.example:lib:1.2.3 } }還有一種情況是依賴傳遞帶來(lái)的沖突。用./gradlew dependencyInsight --dependency lib能看到某個(gè)依賴是被誰(shuí)引入的這是排查沖突最順手的方法。5. 高頻避坑實(shí)錄解壓、報(bào)錯(cuò)與版本兼容5.1 invalid zip archive: could not find EOCD這個(gè)錯(cuò)誤在下載 Gradle zip 或者導(dǎo)入資源包時(shí)經(jīng)常出現(xiàn)。EOCDEnd of Central Directory是 zip 格式結(jié)尾的標(biāo)志性記錄如果找不到基本可以判定zip 文件被截?cái)嗷驌p壞。我遇到過(guò)兩種典型情況第一下載過(guò)程中網(wǎng)絡(luò)不穩(wěn)定文件只下了一半就停了但瀏覽器或下載工具沒(méi)有報(bào)錯(cuò)。解決辦法是刪除文件用校驗(yàn)工具對(duì)比 sha256確認(rèn)完整。第二某些網(wǎng)盤或代理工具會(huì)對(duì)下載的 zip 做二次處理導(dǎo)致文件頭損壞。這種問(wèn)題往往防不勝防建議直接從官方或鏡像地址下載并且用命令行unzip -t gradle-6.5-all.zip測(cè)試完整性。注意could not find EOCD不是解壓工具的鍋是文件本身已經(jīng)壞了。重下文件永遠(yuǎn)比折騰解壓軟件有效。5.2 解壓中文亂碼問(wèn)題很多人在 Windows 上把 Gradle 或其他 zip 包解壓到 Linux 服務(wù)器發(fā)現(xiàn)里面的中文文件名變成了亂碼。原因很簡(jiǎn)單Windows 上壓縮時(shí)默認(rèn)使用 GBK 編碼文件名而 Linux 的 unzip 默認(rèn)按 UTF-8 解碼。解決方案分兩種在 Linux 上使用unzip -O CP936指定編碼unzip -O CP936 gradle-6.5-all.zip如果本機(jī)沒(méi)有-O選項(xiàng)可以用 Python 的 zipfile 模塊指定編碼方式重新解壓。不過(guò) Gradle 本身的包內(nèi)文件名基本都是 ASCII所以這個(gè)問(wèn)題對(duì) Gradle 發(fā)行包影響不大更多是日常處理其他 zip 資源時(shí)要注意。5.3 分卷 zip 和密碼 zip 的坑熱詞里提到的必須有下列壓縮分卷 z01和zip 密碼忘記屬于另一類問(wèn)題。分卷 zip 一般出現(xiàn)在超大文件的拆分壓縮中需要把所有分卷放在同一個(gè)目錄下從第一個(gè)分卷.zip 或 .z01開(kāi)始解壓。關(guān)于 zip 密碼恢復(fù)我不展開(kāi)討論工具只提醒一句如果你自己創(chuàng)建了一個(gè)帶密碼的 zip且密碼丟失暴力破解的時(shí)間成本可能遠(yuǎn)超重新生成文件。更好的習(xí)慣是壓縮時(shí)選擇標(biāo)準(zhǔn)的 AES-256 加密同時(shí)給壓縮包一個(gè)簡(jiǎn)單的說(shuō)明文件記錄密碼涉及到團(tuán)隊(duì)協(xié)作時(shí)用企業(yè)網(wǎng)盤或密鑰管理服務(wù)來(lái)共享文件而不是把帶密碼的壓縮包扔進(jìn)群聊。5.4 IDE 集成問(wèn)題IDEA 版本與 Gradle 版本沖突IntelliJ IDEA 自帶 Gradle 支持但 IDE 內(nèi)置的 Gradle 版本和項(xiàng)目所需版本可能不一致。當(dāng)你用 IDEA 打開(kāi)一個(gè)使用 Gradle 6.5 的項(xiàng)目時(shí)如果 IDE 本身比較新可能會(huì)出現(xiàn)Gradle 版本不兼容或無(wú)法解析依賴的提示。解決辦法是在 IDEA 的 Settings → Build Tools → Gradle 中指定Gradle home為你手動(dòng)安裝的 6.5 目錄而不是使用 IDE 自帶的版本。另外IDEA 新版本對(duì) Gradle 8.x 支持更好老項(xiàng)目用 IDEA 2020.3 到 2021.2 這類版本配合 6.5 反而最穩(wěn)定。6. 版本選型與升級(jí)我的實(shí)際建議6.1 什么情況下繼續(xù)用 6.5如果你的項(xiàng)目是 2021 年前后搭建的用了很多舊插件比如某些內(nèi)部發(fā)布的 gradle 插件只支持 6.x那繼續(xù)鎖定 6.5 是合理的。Gradle 的插件兼容性通常是向前兼容但不保證向后兼容插件作者沒(méi)有跟上新版本升級(jí) Gradle 就會(huì)導(dǎo)致插件崩潰。另一個(gè)是 Android 項(xiàng)目。老版本的 Android Gradle PluginAGP對(duì) Gradle 版本有嚴(yán)格要求AGP 3.x 時(shí)代很多版本只支持 Gradle 6.x。你如果維護(hù)一個(gè)老 Android 工程那么 6.5 可能已經(jīng)是插件支持的上限了。6.2 什么時(shí)候應(yīng)該升級(jí)新項(xiàng)目我不建議從 6.5 起步?,F(xiàn)在 Gradle 8.x 的構(gòu)建速度、Kotlin DSL 支持、配置緩存機(jī)制都比 6.x 強(qiáng)太多。如果你是新建項(xiàng)目直接用最新穩(wěn)定版能少踩很多歷史坑。老項(xiàng)目升級(jí)的話先看兩點(diǎn)插件是否兼容以及 Groovy 腳本的 API 有沒(méi)有廢棄。Gradle 6.5 里很多compile相關(guān)配置在 7.x 已經(jīng)被移除升級(jí)時(shí)要全部替換為implementation。建議按這個(gè)順序操作在gradle-wrapper.properties里改版本號(hào)執(zhí)行./gradlew wrapper --gradle-version 8.x重新生成 wrapper運(yùn)行./gradlew help看有沒(méi)有報(bào)錯(cuò)分模塊運(yùn)行./gradlew compileJava驗(yàn)證最后跑完整build一次不要跨太多版本。6.5 → 7.0 → 7.6 → 8.0 這樣的節(jié)奏比一次性跳躍到 8 更容易定位問(wèn)題。6.3 最后分享一個(gè)我從 6.5 時(shí)代保留至今的習(xí)慣不管用什么版本我都會(huì)在 CI 腳本里加兩步先執(zhí)行./gradlew --stop確保沒(méi)有殘留 daemon 進(jìn)程再執(zhí)行./gradlew clean build --no-daemon做一次干凈構(gòu)建。--no-daemon雖然慢一點(diǎn)但能避免 daemon 緩存帶來(lái)的本地能過(guò)、CI 上掛的詭異問(wèn)題。這個(gè)習(xí)慣從 Gradle 6.5 一直沿用到現(xiàn)在幫我排掉了不少奇奇怪怪的構(gòu)建故障。如果你手頭正好有一個(gè)基于 6.5 的老項(xiàng)目不妨先按這篇文章檢查一下 Wrapper 的 distributionUrl 是否指向了鏡像、本地緩存是否健康、IDEA 里指定的 Gradle 版本對(duì)不對(duì)。處理好這幾個(gè)小點(diǎn)構(gòu)建體驗(yàn)?zāi)芴嵘淮蠼?。本文還有配套的精品資源點(diǎn)擊獲取