文章目錄
一、什麼是 dependency 的 configuration
不同的 configuration
用來引用不同領域(或不同用途)的 dependencies
。
如:implementation、api、testRuntime。
或者說 configuration 用來管理
一批 dependencies。
二、configuration 的繼承與複合
一個 configuration 可以繼承另一個 configuration。子 configuration 會繼承父 configuration 的所有 dependencies。
如 a 繼承了 b(通過 extendsFrom 方法來繼承):
configurations {
a.extendsFrom b
}
在 java 插件中,compileClasspath
繼承了 implementation
,擁有了其聲明的所有 dependencies。compileJava
task 會用到 compileClasspath
。
三、可解析和可消費 configuration
configuration 可用於三個方面:
- 單純地聲明 dependencies
- 被消費者使用,將其管理的一組 dependencies 解析爲文件
- 被生產者使用,公開其管理的 artifacts 及其 dependencies 以供其他項目使用
一個可被解析
的 configuration 的 canBeResolved
屬性爲 true。
一個可被消費
的 configuration 的 canBeConsumed
屬性爲 true。
configurations {
a { canBeResloved = true }
b { canBeConsumed = true }
}
一個可被解析 configuration
往往繼承了一個或多個不可被解析 configuration
。它們的關係類似於抽象類和子類:不可被解析 configuration 不能實例化,可解析 configuration 是它的子類,可實例化(將 dependencies 解析爲文件)。
所以可被解析 configuration
用於管理 dependency,相應的,可被消費 configuration
用於管理 artifact。
canBeResolved、canBeConsumed 屬性默認都爲 true。
java 插件中,implementation 的 canBeResolved、canBeConsumed 屬性都爲 false。
四、自定義 configuration
4.1 現有 configuration 的繼承
configurations {
// 聲明一個自定義 configuration
gdConfiguration
// 使 implementation 繼承於它
implementation.extendsFrom(gdConfiguration)
}
dependencies {
// 使用自定義 configuration: gdConfiguration
// mylib 中的類可以在 app 中正常訪問
gdConfiguration project(":mylib")
}
4.2 自定義 configuration 的解析
configurations {
jasper
}
dependencies {
jasper 'com.github.bumptech.glide:glide:4.9.0'
}
task preCompileJasper {
doLast {
// asPath 會觸發 resolve
println("configurations.jasper.asPath: ${configurations.jasper.asPath}")
}
}
執行 preCompileJasper:
> Task :app:preCompileJasper
configurations.jasper.asPath: ~/.gradle/caches/modules-2/files-2.1/com.github.bumptech.glide/glide/4.9.0/c34f3a0b710a00c62a62683f5f756e6af34183a8/glide-4.9.0.aar:...
asPath 會下載引用的依賴(即 resolve),返回下載後的文件地址。
asPath 即 FileCollection 的 getAsPath() 方法。
如果設置 jasper 的 canBeResolved 屬性爲 false,執行 preCompileJasper 會失敗:
> Task :app:preCompileJasper FAILED
* What went wrong:
Execution failed for task ':app:preCompileJasper'.
> Resolving configuration 'jasper' directly is not allowed
五、dependencies 的種類
5.1 module dependencies
module dependencies 是最常見的 dependencies,指向倉庫中的某個 module。
dependencies {
runtimeOnly group: 'org.springframework', name: 'spring-core', version: '2.5'
runtimeOnly 'org.springframework:spring-core:2.5',
'org.springframework:spring-aop:2.5'
runtimeOnly(
[group: 'org.springframework', name: 'spring-core', version: '2.5'],
[group: 'org.springframework', name: 'spring-aop', version: '2.5']
)
runtimeOnly('org.hibernate:hibernate:3.0.5') {
transitive = true
}
runtimeOnly group: 'org.hibernate', name: 'hibernate', version: '3.0.5', transitive: true
runtimeOnly(group: 'org.hibernate', name: 'hibernate', version: '3.0.5') {
transitive = true
}
}
可以使用一個 String 或一個 Map 來聲明 module dependencies,還可以加上一個配置閉包來補充配置。
map 的所有 key 見 dependencyHandler。
5.2 文件 dependencies
可以直接將一個文件看作 dependency。
dependencies {
antContrib files('ant/antcontrib.jar')
externalLibs files('libs/commons-lang.jar', 'libs/log4j.jar')
deploymentTools(fileTree('tools') { include '*.exe' })
implementation fileTree(include: ['*.jar'], dir: 'libs')
}
這裏注意,一種常見的 aar 的引入方式是:
implementation(name: 'library_1.2', ext: 'aar')
這其實不是一個文件 dependencies
,而是一個 module dependency
,需要將 aar 的目錄設爲 flatDir 倉庫。
如果引用 jar 包時加上 aar,那其實也不用每個 aar 都單獨聲明:
implementation fileTree(include: ['*.jar'], dir: 'libs')
當聲明一個文件 dependency 時,可以通過 builtBy 來聲明生產這個文件的 task:
configurations {
myConfiguration
}
dependencies {
myConfiguration files("$buildDir/classes") {
builtBy 'myCompile'
}
}
task myCompile() {
doLast {
println "myCompile exec"
}
}
task list(dependsOn: configurations.myConfiguration) {
doLast {
// dependsOn 會觸發 resolve
// collect 也會觸發 resolve
println "classpath = ${configurations.myConfiguration.collect { File file -> file.name }}"
}
}
這樣,在 resolve 這個 configuration 時,它 builtBy 的 task 會先執行。
執行 list:
$ ./gradlew list
> Task :app:myCompile
myCompile exec
> Task :app:list
classpath = [classes]
如上,會先執行 myCompile,再執行 list。
5.3 Project dependencies
在 project 自己的 build.gradle 中聲明:
dependencies {
implementation project(':shared')
}
在其他 project 的 build.gradle 中聲明:
project(":app") {
dependencies {
implementation project(':shared')
}
}
一個 module dependencies 可以被該 module 的本地源碼代替,即通過 project dependencies 代替 module dependencies,具體可查看 composite_builds。
5.4 Gradle 特定 dependencies
Gradle 提供了幾個特定的 dependencies。
dependencies {
implementation gradleApi() // 聲明一個當前 Gradle 版本 api 的依賴,用於開發自定義 Gradle task 或 plugin
implementation localGroovy() // 聲明一個當前 Gradle 版本使用的 Groovy 的依賴,用於開發自定義 Gradle task 或 plugin
testImplementation gradleTestKit() // 聲明一個當前 Gradle 版本使用的 TestKit 的依賴,用於測試 Gradle plugin 或 build script
}
六、文檔化 dependencies
Gradle 4.6 及以後支持 because 關鍵字,用於說明使用某個 dependencies 的原因:
dependencies {
implementation('org.ow2.asm:asm:7.1') {
because 'we require a JDK 9 compatible bytecode generator'
}
}
在使用 dependency insight 時,分析報告中會含有 because 的內容。
./gradlew :app:dependencyInsight --configuration debugCompileClasspath --dependency asm