之前對Android Gradle構建的依賴一直傻傻分不清,這段時間正好接入集團的一個二方庫,踩了很多坑,也順帶把Gradle依賴這塊搞清楚了,主要整理了下Gradle依賴的型別、依賴配置、如何檢視依賴、依賴衝突如何解決。
依賴型別
dependencies DSL標籤是標準Gradle API中的一部分,而不是Android Gradle外掛的特性,所以它不屬於android標籤。
依賴有三種方式,如下面的例子:
apply plugin: 'com.android.application'
android { ... }
dependencies {
// Dependency on a local library module
implementation project(":mylibrary")
// Dependency on local binaries
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Dependency on a remote binary
implementation 'com.example.android:app-magic:12.3'
}
複製程式碼
1. 本地library模組依賴
implementation project(":mylibrary")
複製程式碼
這種依賴方式是直接依賴本地庫工程程式碼的(需要注意的是,mylibrary的名字必須匹配在settings.gradle
中include標籤下定義的模組名字)。
2. 本地二進位制依賴
implementation fileTree(dir: 'libs', include: ['*.jar'])
複製程式碼
這種依賴方式是依賴工程中的 module_name/libs/目錄下的Jar檔案
(注意Gradle的路徑是相對於build.gradle檔案來讀取的,所以上面是這樣的相對路徑)。
如果只想依賴單個特定本地二進位制庫,可以如下配置:
implementation files('libs/foo.jar', 'libs/bar.jar')
複製程式碼
3. 遠端二進位制依賴
implementation 'com.example.android:app-magic:12.3'
複製程式碼
上面是簡寫的方式,這種依賴完整的寫法如下:
implementation group: 'com.example.android', name: 'app-magic', version: '12.3'
複製程式碼
group
、name
、version
共同定位一個遠端依賴庫。需要注意的點是,version
最好不要寫成"12.3+"這種方式,除非有明確的預期,因為非預期的版本更新會帶來構建問題。遠端依賴需要在repositories
標籤下宣告遠端倉庫,例如jcenter()
、google()
、maven
倉庫等。
依賴配置
目前Gradle版本支援的依賴配置有:implementation
、api
、compileOnly
、runtimeOnly
和 annotationProcessor
,已經廢棄的配置有:compile
、provided
、apk
、providedCompile
。此外依賴配置還可以加一些配置項,例如AndroidTestImplementation
、debugApi
等等。
常用的是implementation
、api
、compileOnly
三個依賴配置,含義如下:
implementation
與compile對應,會新增依賴到編譯路徑,並且會將依賴打包到輸出(aar或apk),但是在編譯時不會將依賴的實現暴露給其他module,也就是隻有在執行時其他module才能訪問這個依賴中的實現。使用這個配置,可以顯著提升構建時間,因為它可以減少重新編譯的module的數量。建議,儘量使用這個依賴配置。
api
與compile對應,功能完全一樣,會新增依賴到編譯路徑,並且會將依賴打包到輸出(aar或apk),與implementation不同,這個依賴可以傳遞,其他module無論在編譯時和執行時都可以訪問這個依賴的實現,也就是會洩漏一些不應該不使用的實現。舉個例子,A依賴B,B依賴C,如果都是使用api配置的話,A可以直接使用C中的類(編譯時和執行時),而如果是使用implementation配置的話,在編譯時,A是無法訪問C中的類的。
compileOnly
與provided對應,Gradle把依賴加到編譯路徑,編譯時使用,不會打包到輸出(aar或apk)。這可以減少輸出的體積,在只在編譯時需要,在執行時可選的情況,很有用。
runtimeOnly
與apk對應,gradle新增依賴只打包到APK,執行時使用,但不會新增到編譯路徑。這個沒有使用過。
annotationProcessor
與compile對應,用於註解處理器的依賴配置,這個沒用過。
檢視依賴樹
可以檢視單個module或者這個project的依賴,通過執行依賴的Gradle任務,如下:
1、View
-> Tools Windows
-> Gradle
(或者點選右側的Gradle欄
);
2、展開 AppName
-> Tasks
-> android
,然後雙擊執行AndroidDependencies
。執行完,就會在Run視窗打出依賴樹了。
依賴衝突解決
隨著很多依賴加入到專案中,難免會出現依賴衝突,出現依賴衝突如何解決?
定位衝突
依賴衝突可能會報類似下面的錯誤:
Program type already present com.example.MyClass
複製程式碼
通過查詢類的方式(command + O)定位到衝突的依賴,進行排除。
如何排除依賴
1、dependencies中排除(細粒度)
compile('com.taobao.android:accs-huawei:1.1.2@aar') {
transitive = true
exclude group: 'com.taobao.android', module: 'accs_sdk_taobao'
}
複製程式碼
2、全域性配置排除
configurations {
compile.exclude module: 'cglib'
//全域性排除原有的tnet jar包與so包分離的配置,統一使用aar包中的內容
all*.exclude group: 'com.taobao.android', module: 'tnet-jni'
all*.exclude group: 'com.taobao.android', module: 'tnet-so'
}
複製程式碼
3、禁用依賴傳遞
compile('com.zhyea:ar4j:1.0') {
transitive = false
}
configurations.all {
transitive = false
}
複製程式碼
還可以在單個依賴項中使用@jar識別符號忽略傳遞依賴:
compile 'com.zhyea:ar4j:1.0@jar'
複製程式碼
4、強制使用某個版本
如果某個依賴項是必需的,而又存在依賴衝突時,此時沒必要逐個進行排除,可以使用force
屬性標識需要進行依賴統一。當然這也是可以全域性配置的:
compile('com.zhyea:ar4j:1.0') {
force = true
}
configurations.all {
resolutionStrategy {
force 'org.hamcrest:hamcrest-core:1.3'
}
}
複製程式碼
5、在打包時排除依賴
先看一個示例:
task zip(type: Zip) {
into('lib') {
from(configurations.runtime) {
exclude '*unwanted*', '*log*'
}
}
into('') {
from jar
from 'doc'
}
}
複製程式碼
程式碼表示在打zip包的時候會過濾掉名稱中包含“unwanted”
和“log”
的jar包。這裡呼叫的exclude方法的引數和前面的例子不太一樣,前面的引數多是map結構,這裡則是一個正規表示式字串。
也可以使用在打包時呼叫include方法選擇只打包某些需要的依賴項:
task zip(type: Zip) {
into('lib') {
from(configurations.runtime) {
include '*ar4j*', '*spring*'
}
}
into('') {
from jar
from 'doc'
}
}
複製程式碼
主要是使用dependencies中排除和全域性配置排除。