先安利一個查詢項目依賴的命令:./gradlew 模塊名:dependencies 。
一、exclude
用法:exclude group:' ', module: ' ' 【 group和module兩個參數可分別單獨使用 】
說明:排除某個依賴,可解決部分傳遞依賴。
使用場景:
- 解決依賴沖突。若兩個模塊使用相同 jar 包的不同版本,gradle 默認會使用最新版本的 jar 包,此時可以通過 exclude 排除沖突。(版本沖突帶來的問題最主要是API類或方法移除。)
- 運行期無需此模塊。
- 傳遞依賴無法找到時,可通過 exclude 排除。
- 版權原因需排除。
compile 'com.android.support:support-v4:26.1.0'
// 單獨排除某個模塊中的依賴
compile('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0@aar') {
exclude group: 'com.android.support'
}
// 排除所有子依賴中的support依賴,統一使用主項目中的版本
configurations {
all*.exclude group: 'com.android.support'
}
用法:主工程使用的 support 包版本為 26.1.0,使用 exclude group: 'com.android.support' 可以將 advrecyclerview 模塊中的 support 排除掉,統一使用主工程的 v26.1.0 版本。不管advrecyclerview依賴的該support包版本時高於還是低於主工程版本。
假設 advrecyclerview 中依賴的 support相關版本為 27.0.0,排除依賴前,項目依賴關系為:
project :shop
| + - com.android.support:appcompat-v7:26.1.0 ()
| + - com.android.support:support-v4:26.1.0 ()
| + - com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0
| | + - - - com.android.support:appcompat-v7:27.0.0 -> 26.1.0 ()
| | \ - - - com.android.support:recyclerview-v7:27.0.0 -> 26.1.0
| | + - - - - - com.android.support:support-annotations:26.1.0
| | + - - - - - com.android.support:support-compat:26.1.0 ()
| | \ - - - - - com.android.support:support-core-ui:26.1.0 (*)
對應的在build后,External Libraries 中會同時存在 support v27.0.0 和 v26.1.0 兩種版本的aar依賴。
排除 support 依賴后,External Libraries 就只會存在 v26.1.0 版本的aar。對應的依賴關系如下:
project :shop
| + - com.android.support:appcompat-v7:26.1.0 ()
| + - com.android.support:support-v4:26.1.0 ()
| + - com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0
二、transitive
用法:transitive = true | false
說明:是否傳遞本身的依賴給宿主程序(使用傳遞依賴時,Gradle 會將傳遞依賴一起下載下來。compile 默認是開啟傳遞依賴)
// 統一指定 transitive
configurations.all {
transitive = false
}
// 單獨指定依賴項的 transitive
compile('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0@aar') {
transitive = false
}
transitive = true,依賴同於沒有使用 exclude 排除依賴 ,每個包的依賴項都會被遞歸分析並添加進來。
transitive = false,則依賴關系同於用 exclude 排除依賴。
Tips: exclude 和 transitive 可以同時使用,exclude會排除 transitive=true時的一些傳遞依賴。
三、force
用法:force = true
作用:強制使用某個版本。出現沖突時,優先使用該版本解決。
// 強制使用 support-v4 26.1.0版本
compile('com.android.support:support-v4:26.1.0') {
force = true
}
四、動態版本(不建議使用)
使用場景:保持工程依賴都是最新版本。
使用方式:+,可以讓gradle每次構建時檢查遠程倉庫是否存在最新版本,若存在則下載。也可指定某個大版本下的最新子版本,1.+,表示始終依賴最新的 1.x 版本。
compile 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.+'
缺點:
- 減低構建速度並且會提高構建失敗風險;
- 新版本可能帶來兼容性問題。
五、綜合實例
compile('org.hibernate:hibernate:3.1') {
// 沖突時優先使用該版本
force = true
// 依據構建名稱排除
exclude module: 'cglib'
// 依據組織名稱排除
exclude group: 'org.jmock'
// 依據組織名稱+構件名稱排除
exclude group: 'org.unwanted', module: 'iAmBuggy'
// 為本依賴關閉依賴傳遞特性
transitive = false
}
六、問題
1.項目中多個模塊依賴同一個依賴 D 的不同版本,如何保持每個模塊直接使用自己本身 compile 的依賴版本呢?
A:如果是直接 compile 包含不同版本的依賴,會造成依賴沖突。有一種方式可以直接將模塊打包成本地 jar 。打包成本地 aar 文件,也是不行,因為本地 aar 依賴,需要外部也 compile aar 中依賴的一些架包,否則會找不到。
另一種方式就很有效保證 各個模塊保持自己依賴的版本,而不用在意其他版本並且擔心產生沖突。具體如下:
configurations.all {
// 遍歷所有的依賴,根據 moduleName 使用對應的版本。確實可行
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (requested.name.startsWith("multidex")) {
details.useVersion '26.1.0'
} else if (requested.name.startsWith("advrecyclerview")) {
details.useVersion '27.0.0'
} else {
details.useVersion '25.3.0'
}
}
}
}
七、本地aar依賴問題
場景:主工程app -> shop模塊 -> 依賴本地aar
問題:在主工程依賴 shop 模塊的遠程依賴時,無法找到依賴的本地 aar 相關。
解決:將 本地 aar 放到遠端,也是用遠程依賴。
原因:主要在於Android 3.0 后本地 aar 依賴無法越級傳遞依賴。可以看遠端 shop模塊 maven打包時生成的 .pom 文件,查看具體依賴,發現gradle 會把本地 aar 依賴也當做一份遠端依賴進行配置,但是沒有group等信息,如此在主工程中依賴 shop 模塊是,直接編譯不通過,因為會視為遠端倉庫的依賴,但實際並不存在。(根本原因未知)
問題:本地 jar 依賴和 本地 aar 依賴區別。
- jar 文件只包含編譯好的 .class 文件和清單文件,不包含資源文件。所以如果沒有 res 資源文件,可以在打包時,將 packaging 配置為 jar 格式;
- aar 文件包含 class 以及 /res 目錄下的所有資源文件。
-查看 gradle 下載的遠程依賴區別就很明顯:

