Gradle使用阿里雲鏡像加速的正確方式

先說結果

這是總結之後的init.gradle配置,很直觀,好理解,位置在USER_HOME/.gradle/

allprojects {
    repositories {
        maven {
            name "ALIYUN_CENTRAL_URL" // name 可以不需要
            url 'https://maven.aliyun.com/nexus/content/repositories/central'
        }
        maven {
            name "ALIYUN_JCENTER_URL"
            url 'https://maven.aliyun.com/nexus/content/repositories/jcenter'
        }
        maven {
            name "ALIYUN_GOOGLE_URL"
            url 'https://maven.aliyun.com/nexus/content/repositories/google'
        }
    }
}

錯誤示例

你能搜到的幾乎所有文章的init.gradle都是這個:
(CSDN代碼塊不支持groovy高亮拿kotlin湊合了下)

allprojects {
    repositories {
        def ALIYUN_REPOSITORY_URL = 'http://maven.aliyun.com/nexus/content/groups/public'
        def ALIYUN_JCENTER_URL = 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
        all {
            ArtifactRepository repo ->
                if (repo instanceof MavenArtifactRepository) {
                    def url = repo.url.toString()
                    if (url.startsWith('https://repo1.maven.org/maven2')) {
                        project.logger.lifecycle "Repository ${repo.url} replaced by $ALIYUN_REPOSITORY_URL."
                        remove repo
                    }
                    if (url.startsWith('https://jcenter.bintray.com/')) {
                        project.logger.lifecycle "Repository ${repo.url} replaced by $ALIYUN_JCENTER_URL."
                        remove repo
                    }
                }
        }
        maven {
            url ALIYUN_REPOSITORY_URL
            url ALIYUN_JCENTER_URL
        }
    }
}

問題一

我們來看這個init.gradle到底做了什麼:

1.定義阿里雲鏡像倉庫地址

2.如果項目裏引入了mevenCentraljcenter,刪掉,打印一個log

3.引入阿里雲鏡像倉庫

這樣基本上沒有問題,實際上gradle關於init腳本的文檔中就有這麼寫的示例,但原示例的內容是"我只想使用公司內部的repo,其他倉庫我都不要",這並不符合我的需求,樸素的想法時:如果阿里雲鏡像有該依賴,優先使用阿里雲來加速;如果沒有,再去原有倉庫下載。

而上面的腳本在阿里雲鏡像沒有及時更新or其他原因沒有找到需要的庫時,依賴就會直接出錯。

事實上,gradle文檔中Declaring module dependencies部分提到:

A project can have multiple repositories. Gradle will look for a dependency in each repository in the order they are specified, stopping at the first repository that contains the requested module.

在有多個倉庫時,gradle會根據順序依次搜索依賴,在找到第一個符合條件的倉庫就不再看後面了。

init script部分中也有這樣的例子:

在這裏插入圖片描述
可以看出init.gradle執行在build之前,在其中添加的內容最終會放在項目build.gradle相同位置的前面。

然後所以上面腳本的第2步去刪掉原有倉庫是沒必要的。可以同時保留原倉庫和鏡像倉庫,init腳本會保證鏡像倉庫排在依賴順序的前面。

其實實際上阿里雲鏡像還是很全的(真的是不是我也不造啊),但有的文章就比較離譜,加一個阿里雲Jcenter,把mavenCentral都給刪了。

問題二

上面的腳本中,引入鏡像地址時是這樣寫的

maven {
     url ALIYUN_REPOSITORY_URL
     url ALIYUN_JCENTER_URL
}

這就純粹是不瞭解Groovy和Gradle DSL了,可以在AS中按住command(mac)點擊看這個url的定義,它其實是一個void setUrl(Object url)函數,所以寫兩個並不會都加上,前一個會失效
在這裏插入圖片描述
這也很奇怪,很多文章都提到在項目中添加鏡像和定義init.gradle兩種方式,在項目中定義時就能分開寫maven {},到了init.gradle就千篇一律放一塊了。很神祕🤔。

補充

  • 你可以看到我的配置裏多了一個鏡像倉庫地址,實際上阿里雲提供maven鏡像的不止這幾個,

    可以在這裏找到,你喜歡的都可以往上加。

  • 如果使用了定義buildSrc這種方式來管理gradle配置,init 腳本是會失效的

  • 想要知道項目裏是否真的有依賴到鏡像倉庫,可以這樣:

  1. 在AS工程build.gradle中新增一個task,sync
 buildscript {
     ...
 }
 allprojects {
     ...
 }
 // 寫個a方便後面截圖時排最前..
 task aShowRepo { 
      println "All repos:"
      println repositories.collect { it.name }
      repositories.each {
          println "repository: ${it.name} ('${it.url}')"
      }
 }
  1. 點開側邊欄,一路找到自定義的task,右鍵,選擇Execute After Sync

在這裏插入圖片描述
3. 重新sync或者build項目,可以看到輸出,印證了init.gradle中定義的倉庫確實會排在前面
在這裏插入圖片描述
沒毛病
在這裏插入圖片描述

參考

Gradle官方文檔

還是Gradle官方文檔

阿里雲公共代理庫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章