譯者:個別地方翻譯可能不是很好,反復讀了幾遍,內容對自己幫助還是挺大的。
前段時間我們談了Gradle,今天我們將會討論Gradle的依賴管理,對于Android來說是一個偉大的功能。

使用Gradle你可以用類似Maven的方式輕松管理一些依賴像Play Services,support libraries,或者其他庫。既然這樣,那么你可以反問自己一些關于管理依賴的問題:
- 當一個項目中的2個依賴同時依賴某個依賴,而它們的各自依賴的版本號有沖突的時候,怎么進行管理?(a,b同時依賴c ,a依賴c1.1,b依賴c2.1)
- 什么是傳遞依賴解析?
- 可選依賴的作用?
本文會用一些我們熟悉的例子清晰得來解決這些問題。
演示項目
本文討論的例子都放在了Github上面,你可以clone下來自己嘗試一下。
怎么添加依賴
例子
Calligraphy是一個知名的管理字體的android庫,為了用它,你需要在項目build.gradle添加它作為項目的一個依賴:
compile 'uk.co.chrisjenx:calligraphy:2.1.0'
這是一個很典型用來添加依賴的例子,但是它自身有其他依賴呢?為了列出你項目中所有的依賴(包含依賴的子依賴)你可以用下面這個命令:
./gradlew dependencies app:dependencies
這個命令會列出app module每一個configuration的依賴,為了減少輸出內容我們只對compile configuration感興趣。
./gradlew dependencies app:dependencies --configuration compile
我們獲取到下面的結果(譯者:自己可以查看下自己控制臺輸出更清晰):
compile - Classpath for compiling the main sources.
--- uk.co.chrisjenx:calligraphy:2.1.0
\--- com.android.support:appcompat-v7:22.1.1
\ --- com.android.support:support-v4:22.1.1
\ --- com.android.support:support-annotations:22.1.1
我們可以看到Calligraphy依賴appcompat-v7,而v7本身又依賴appcompat-v4,v4反過來又依賴support-annotations,這些依賴不用我們添加默認就解決好了,它們被傳遞解決了。
可傳遞性依賴
例子
要是我們的app module已經使用了appcompat-v7,但是,是更高版本23.1.1,那么最終app使用的是哪個版本的appcompat-v7,是Calligraphy依賴的22.1.1嗎?讓我們運行命令再來分析下:
compile - Classpath for compiling the main sources.
+--- uk.co.chrisjenx:calligraphy:2.1.0
| --- com.android.support:appcompat-v7:22.1.1 -> 23.1.1
| --- com.android.support:support-v4:23.1.1
| --- com.android.support:support-annotations:23.1.1
--- com.android.support:appcompat-v7:23.1.1 (*)
calligraphy依賴的appcompat-v7:22.1.1已經變成了appcompat-v7:23.1.1,默認,依賴解析是可傳遞的,也就是以遞歸的方式解析所有依賴(包括依賴的依賴),如果有沖突則取高的版本號。這就是為什么support-v4和support-annotations會自動引入到我的app module(我們沒有必要在build.gradle進行添加它們了)
依賴解析策略
例子
我們可以添加下面的代碼塊到我們的build.gradle中用來通知我們是否項目的同一個依賴有2個不同版本:
configurations.all {
resolutionStrategy {
failOnVersionConflict()
}
}
再build時上面的代碼會觸發錯誤,強制我們手動解決版本沖突。默認情況下,Gradle用它自己的依賴解析策略,當發生版本沖突時,它會使用高版本號,你也可以定義自己的解析策略,類似上面這個(文檔)
過濾依賴
例子
此外,我們可以直接配置Gradle怎樣建立依賴,例如,如果查看simple-xml庫,依賴分析結果如下:
compile - Classpath for compiling the main sources.
--- org.simpleframework:simple-xml:2.7.1
+--- stax:stax-api:1.0.1
+--- stax:stax:1.2.0
| \--- stax:stax-api:1.0.1
\--- xpp3:xpp3:1.1.3.3
配置是無法通過編譯,因為下面的原因:
- xpp3本身就直接被包含在Android framework中,我們不能包含同包名,同類名的另外一個版本的xpp3
- stax用的是android framework受保護的包名(java.xml.*),然而不用擔憂simple-xml可以工作在Android上因為它的依賴stax是可選的
(stax的可用性是在運行時被檢查)
但是我們需要修改build.gradle以便編譯期間忽略stax(順便說一下,編譯系統足夠聰明會自動忽略xpp3,只是會顯示一個警告),我們可以用下面的語法排除stax
compile('org.simpleframework:simple-xml:2.7.1'){
exclude module: 'stax'
exclude module: 'stax-api'
exclude module: 'xpp3' // optional
}
相應的DSL文檔請查看這里
給library開發者
有了前面的例子我們可以看到沒有stax,simple-xml也可以工作,如果我們看一下它的pom.xml,我們會發現stat不是一個可選依賴。但是它卻可以定義為一個可選依賴。讓我們細想一下:一個library L依賴一個可選的library O,L傳遞依賴解析的時候不會包含O依賴。
在simple-xml的例子中,如果stax和xpp3是可選依賴,我們就可以直接像下面聲明simple-xml依賴:
compile 'org.simpleframework:simple-xml:2.7.1'
實際上,Retrofit1就是這種情況,OKHttp是一個可選的依賴。那么在運行時,如果OkHttp可用,Retrofit會使用OkHttp作為默認的http client,否則將使用Retrofit用到的平臺提供的默認http client,我們還注意到Retrofit 1沒有使用Gradle而是Maven。我們可以解釋這個選擇是因為聲明可選依賴還沒有被Gradle原生支持。但是目前有一些解決方案可以讓你實現:
- 如這里解釋,可以手動使用可選依賴
- 這個插件(gradle-extra-configurations-plugin)可以給Gradle build system帶來可選依賴
總結
通過Gradle進行依賴管理是非常有幫助的。清晰的理解怎么配置這些依賴可以讓你以一種有意義的方式管理依賴關系在android項目周期的演變。
不僅如此,一個非常精確的庫依賴配置對開發人員幫助很大,可以很容易地包括在其他項目,如Retrofit.
特別感謝Adrien Couque給予我的幫助。