Android Gradle使用技巧-gradle使用詳細介紹
Android Gradle使用詳解(一)--設置applicationId
利用 Android Studio 中的 Gradle 構建系統(tǒng)备闲,您可以輕松地將外部二進制文件或其他庫模塊作為依賴項添加到您的 build 中阻逮。這些依賴項可位于您的計算機上或遠程代碼庫中,并且它們聲明的所有傳遞依賴項也會自動包含在內(nèi)铣鹏。
注意:指定依賴項時惊窖,不應使用動態(tài)版本號刽宪,如 'com.android.tools.build:gradle:3.+'。使用此功能可能會導致意外的版本更新和難以解析版本差異界酒。
一圣拄、依賴項類型
如需向您的項目添加依賴項,請在 build.gradle 文件的 dependencies 代碼塊中指定依賴項配置毁欣,如 implementation庇谆。
例如,應用模塊的以下 build.gradle 文件包含三種不同類型的依賴項:
apply plugin: 'com.android.application'
android { ... }
dependencies {
// 對本地庫模塊的依賴
implementation project(":mylibrary")
//或者
implementation project(path: ":mylibrary")
// 對本地二進制文件的依賴
implementation fileTree(dir: 'libs', include: ['*.jar'])
// 對遠程二進制文件的依賴
implementation 'com.example.android:app-magic:12.3'
}
其中每種依賴項配置都請求不同種類的庫依賴項署辉,如下所示:
1族铆、本地庫模塊依賴項
implementation project(':mylibrary')
這聲明了對一個名為“mylibrary”(此名稱必須與在您的 settings.gradle 文件中使用 include: 定義的庫名稱相符)的 Android 庫模塊的依賴關系。在構建您的應用時哭尝,構建系統(tǒng)會編譯該庫模塊哥攘,并將生成的編譯內(nèi)容打包到 APK 中。
2材鹦、本地二進制文件依賴項
implementation fileTree(dir: 'libs', include: ['*.jar'])
Gradle 聲明了對項目的 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'
這聲明了對“com.example.android”命名空間組內(nèi)的 12.3 版“app-magic”庫的依賴關系栅葡。
注意:此類遠程依賴項要求您聲明適當?shù)倪h程代碼庫,Gradle 應在其中查找相應的庫尤泽。如果本地不存在相應的庫欣簇,則當 build 需要它時(例如,當您點擊 Sync Project with Gradle Files 圖標或運行 build 時)坯约,Gradle 會從遠程站點提取它熊咽。
二、依賴項配置
在 dependencies 代碼塊內(nèi)闹丐,您可以從多種不同的依賴項配置中選擇其一(如上面所示的 implementation)來聲明庫依賴項横殴。每種依賴項配置都向 Gradle 提供了有關如何使用該依賴項的不同說明。下表介紹了您可以對 Android 項目中的依賴項使用的各種配置卿拴。此表還將這些配置與自 Android Gradle 插件 3.0.0 起棄用的配置進行了比較
新配置 | 已棄用配置 | 行為 |
---|---|---|
implementation | compile | Gradle 會將依賴項添加到編譯類路徑衫仑,并將依賴項打包到構建輸出梨与。不過,當您的模塊配置 implementation 依賴項時文狱,會讓 Gradle 了解您不希望該模塊在編譯時將該依賴項泄露給其他模塊粥鞋。也就是說,其他模塊只有在運行時才能使用該依賴項瞄崇。 注意:使用此依賴項配置代替 api 或 compile(已棄用)可以顯著縮短構建時間陷虎,因為這樣可以減少構建系統(tǒng)需要重新編譯的模塊數(shù)。例如杠袱,如果 implementation 依賴項更改了其 API,Gradle 只會重新編譯該依賴項以及直接依賴于它的模塊窝稿。大多數(shù)應用和測試模塊都應使用此配置楣富。 |
api | compile | Gradle 會將依賴項添加到編譯類路徑和構建輸出。當一個模塊包含 api 依賴項時伴榔,會讓 Gradle 了解該模塊要以傳遞方式將該依賴項導出到其他模塊纹蝴,以便這些模塊在運行時和編譯時都可以使用該依賴項。 注意:此配置的行為類似于 compile(現(xiàn)已棄用)踪少,但使用它時應格外小心塘安,只能對您需要以傳遞方式導出到其他上游消費者的依賴項使用它。這是因為援奢,如果 api 依賴項更改了其外部 API兼犯,Gradle 會在編譯時重新編譯所有有權訪問該依賴項的模塊。因此集漾,擁有大量的 api 依賴項會顯著增加構建時間切黔。除非要將依賴項的 API 公開給單獨的模塊,否則庫模塊應改用 implementation 依賴項具篇。 |
compileOnly | provided | Gradle 只會將依賴項添加到編譯類路徑(也就是說纬霞,不會將其添加到構建輸出)。如果您創(chuàng)建 Android 模塊時在編譯期間需要相應依賴項驱显,但它在運行時可有可無诗芜,此配置會很有用。如果您使用此配置埃疫,那么您的庫模塊必須包含一個運行時條件伏恐,用于檢查是否提供了相應依賴項,然后適當?shù)馗淖冊撃K的行為熔恢,以使該模塊在未提供相應依賴項的情況下仍可正常運行脐湾。這樣做不會添加不重要的瞬時依賴項,因而有助于減小最終 APK 的大小叙淌。注意:您不能將 compileOnly 配置與 AAR 依賴項配合使用秤掌。 |
runtimeOnly | apk | Gradle 只會將依賴項添加到構建輸出愁铺,以便在運行時使用。也就是說闻鉴,不會將其添加到編譯類路徑茵乱。 |
annotationProcessor | compile | 如需添加對作為注釋處理器的庫的依賴關系,您必須使用 annotationProcessor 配置將其添加到注釋處理器類路徑孟岛。這是因為瓶竭,使用此配置可以將編譯類路徑與注釋處理器類路徑分開,從而提高構建性能渠羞。如果 Gradle 在編譯類路徑上找到注釋處理器斤贰,則會禁用避免編譯功能,這樣會對構建時間產(chǎn)生負面影響(Gradle 5.0 及更高版本會忽略在編譯類路徑上找到的注釋處理器)次询。如果 JAR 文件包含以下文件荧恍,則 Android Gradle 插件會假定依賴項是注釋處理器:META-INF/services/javax.annotation.processing.Processor。如果插件檢測到編譯類路徑上包含注釋處理器屯吊,則會生成構建錯誤送巡。 |
lintChecks | 使用此配置可以添加您希望 Gradle 在構建項目時執(zhí)行的 lint 檢查.注意:使用 Android Gradle 插件 3.4.0 及更高版本時,此依賴項配置不再將 lint 檢查打包在 Android 庫項目中盒卸。如需將 lint 檢查依賴項包含在 AAR 庫中骗爆,請使用下面介紹的 lintPublish 配置。 | |
lintPublish | 在 Android 庫項目中使用此配置可以添加您希望 Gradle 編譯成 lint.jar 文件并打包在 AAR 中的 lint 檢查蔽介。這會使得使用 AAR 的項目也應用這些 lint 檢查摘投。如果您之前使用 lintChecks 依賴項配置將 lint 檢查包含在已發(fā)布的 AAR 中,則需要遷移這些依賴項以改用 lintPublish 配置虹蓄。 |
1.為構建變體添加依賴
以上配置會將依賴項應用于所有構建變體谷朝。如果您只想為特定的構建變體源代碼集或測試源代碼集聲明依賴項,則必須將配置名稱的首字母大寫武花,并在其前面加上構建變體或測試源代碼集的名稱作為前綴圆凰。
例如,如需只向“free”產(chǎn)品變種添加 implementation 依賴項(使用遠程二進制文件依賴項)体箕,請使用如下所示的代碼:
dependencies {
freeImplementation 'com.google.firebase:firebase-ads:9.8.0'
}
不過专钉,如果您想為將產(chǎn)品變種和構建類型組合在一起的變體添加依賴項,就必須在 configurations 代碼塊中初始化配置名稱累铅。以下示例向“freeDebug”構建變體添加了 runtimeOnly 依賴項(使用本地二進制文件依賴項):
configurations {
// 為freeDebugRuntimeOnly依賴項初始化一個占位符配置跃须。
freeDebugRuntimeOnly {}
}
dependencies {
freeDebugRuntimeOnly fileTree(dir: 'libs', include: ['*.jar'])
}
如需為本地測試和插樁測試添加 implementation 依賴項,請使用如下所示的代碼:
dependencies {
// 僅為本地測試添加遠程二進制依賴項娃兽。
testImplementation 'junit:junit:4.12'
// 僅為已檢測的測試APK添加遠程二進制依賴項菇民。
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
不過,某些配置在這種情況下沒有意義。例如第练,因為其他模塊不能依賴于 androidTest阔馋,所以如果您使用 androidTestApi 配置,會收到以下警告:
WARNING: Configuration 'androidTestApi' is obsolete and has been replaced with
'androidTestImplementation'.
2.使用變體感知型依賴項管理機制
Android 插件 3.0.0 及更高版本包含一種新的依賴項機制娇掏,該機制可在使用庫時自動匹配變體呕寝。這意味著,應用的 debug 變體會自動使用庫的 debug 變體婴梧,依此類推下梢。在使用變種時,這種機制也同樣適用 - 應用的 freeDebug 變體將使用庫的 freeDebug 變體塞蹭。
Android 插件 3.0.0 及更高版本包含一種新的依賴項機制孽江,該機制可在使用庫時自動匹配變體。這意味著番电,應用的 debug 變體會自動使用庫的 debug 變體竟坛,依此類推。在使用變種時钧舌,這種機制也同樣適用 - 應用的 freeDebug 變體將使用庫的 freeDebug 變體。
為了讓插件準確匹配變體涎跨,您需要在無法進行直接匹配的情況下提供匹配回退機制洼冻。不妨假設您的應用配置了一個名為“staging”的構建類型,但該應用的一個庫依賴項沒有進行相應配置隅很。當插件嘗試構建“staging”版本的應用時撞牢,它不知道要使用哪個版本的庫,因此您將看到一條與以下內(nèi)容類似的錯誤消息:
Error:Failed to resolve: Could not resolve project :mylibrary.Required by: project :app
3.解決與變體匹配相關的構建錯誤
- 編譯錯誤原因:您的應用包含庫依賴項不包含的構建類型
例如叔营,您的應用包含“staging”版本類型屋彪,但依賴項僅包含“debug”和“release”版本類型。
解決方案:使用 matchingFallbacks 為給定的構建類型指定替代匹配绒尊,如下所示:android { buildTypes { debug {} release {} staging { //指定后備的構建類型的排序列表畜挥,當依賴項不包含“ staging”構建類型。您可以指定一個婴谱,然后插件選擇第一個可用的構建類型添在依賴項蟹但。 matchingFallbacks = ['debug', 'qa', 'release'] } }
}
```
- 編譯錯誤原因:對于應用及其庫依賴項中均存在的給定變種維度,您的應用包含庫不包含的變種谭羔。
例如华糖,您的應用及其庫依賴項都包含“tier”變種維度。不過瘟裸,應用中的“tier”維度包含“free”和“paid”變種客叉,但依賴項中的同一維度僅包含“demo”和“paid”變種。
解決方案:使用 matchingFallbacks 為應用的“free”產(chǎn)品變種指定替代匹配,如下所示:android { defaultConfig{ // 不要在defaultConfig塊中配置matchFallbacks兼搏。相反卵慰,您必須在productFlavors塊中添加他; } flavorDimensions 'tier' productFlavors { paid { dimension 'tier' // 因為依賴項已在其依賴項中包含“付費”的形式“層級”維度向族,您無需提供后備列表代表“付費”變體呵燕。 } free { dimension 'tier' matchingFallbacks = ['demo', 'trial'] } }
}
```
- 編譯錯誤原因:庫依賴項包含您的應用不包含的變種維度
例如,庫依賴項包含“minApi”維度的變種件相,但您的應用僅包含“tier”維度的變種再扭。因此,當您要構建“freeDebug”版本的應用時夜矗,插件不知道是使用“minApi23Debug”還是“minApi18Debug”版本的依賴項泛范。
解決方案:在 defaultConfig 代碼塊中使用 missingDimensionStrategy 指定插件應從每個缺失維度中選擇的默認變種,如以下示例所示紊撕。您也可以替換在 productFlavors 代碼塊中的選擇罢荡,讓每一個變種都可以為缺失維度指定一個不同的匹配策略。android { defaultConfig{ // 指定插件應嘗試從中使用的變體的排序列表給定的尺寸下面告訴插件对扶,當遇到包含“ minApi”維的依賴項区赵,應選擇“ minApi18”變體。您可以包括其他變體名稱以提供對維度的后備列表進行排序浪南。 missingDimensionStrategy 'minApi', 'minApi18', 'minApi23' // 您應該為每個屬性指定一個missingDimensionStrategy屬性存在于本地依賴項中但不存在于您的應用程序中笼才。 missingDimensionStrategy 'abi', 'x86', 'arm64' } flavorDimensions 'tier' productFlavors { free { dimension 'tier' // 您可以覆蓋產(chǎn)品變體的默認選擇通過配置另一個missingDimensionStrategy屬性進行級別用于“ minApi”維度。 missingDimensionStrategy 'minApi', 'minApi23', 'minApi18' } paid {} }
}
```
4.排除傳遞依賴項
隨著應用的范圍不斷擴大络凿,它可能會包含許多依賴項骡送,包括直接依賴項和傳遞依賴項(應用中導入的庫所依賴的庫)。如需排除不再需要的傳遞依賴項絮记,您可以使用 exclude 關鍵字摔踱,如下所示:
dependencies {
implementation('some-library') {
exclude group: 'com.example.imgtools', module: 'native'
}
}
三、遠程代碼庫
當您的依賴項不是本地庫或文件樹時怨愤,Gradle 會在 build.gradle 文件的 repositories 代碼塊中指定的所有在線代碼庫中查找相關文件派敷。各個代碼庫的列出順序決定了 Gradle 在這些代碼庫中搜索各個項目依賴項的順序。例如撰洗,如果從代碼庫 A 和 B 均可獲得某個依賴項膀息,而您先列出了代碼庫 A,則 Gradle 會從代碼庫 A 下載該依賴項了赵。
默認情況下潜支,新的 Android Studio 項目會將 Google 的 Maven 代碼庫和 JCenter 指定為項目的頂級 build.gradle 文件中的代碼庫位置,如下所示:
allprojects {
repositories {
google()
jcenter()
}
}
如果您要從 Maven 中央代碼庫獲取某些內(nèi)容柿汛,則添加 mavenCentral()冗酿;對于本地代碼庫埠对,則使用 mavenLocal():
allprojects {
repositories {
google()
jcenter()
mavenCentral()
mavenLocal()
}
}
或者,您也可以按如下方式聲明特定的 Maven 或 Ivy 代碼庫:
allprojects {
repositories {
maven {
url "https://repo.example.com/maven2"
}
maven {
url "file://local/repo/"
}
ivy {
url "https://repo.example.com/ivy"
}
}
}
四裁替、依賴項順序
依賴項的列出順序指明了每個庫的優(yōu)先級:第一個庫的優(yōu)先級高于第二個项玛,第二個庫的優(yōu)先級高于第三個,依此類推弱判。在合并資源或?qū)⑶鍐卧貜膸熘泻喜⒌綉弥袝r襟沮,此順序很重要。
例如昌腰,如果您的項目聲明以下內(nèi)容:
- 依賴 LIB_A 和 LIB_B(按此順序)
- LIB_A 依賴于 LIB_C 和 LIB_D(按此順序)
- LIB_B 也依賴于 LIB_C
那么开伏,扁平型依賴項順序?qū)⑷缦滤荆?/li>
- LIB_A
- LIB_D
- LIB_B
- LIB_C
這可以確保 LIB_A 和 LIB_B 都可以替換 LIB_C;并且 LIB_D 的優(yōu)先級仍高于 LIB_B遭商,因為 LIB_A(依賴前者)的優(yōu)先級高于 LIB_B固灵。
五、查看模塊依賴項
一些直接依賴項可能具有自己的依賴項劫流。此類依賴項稱為“傳遞依賴項”巫玻。Gradle 將會自動為您收集并添加這些傳遞依賴項祠汇,無需您手動逐一加以聲明。Android Plugin for Gradle 提供了一項任務可很,用來列出 Gradle 為給定模塊解析的依賴項。
對于每個模塊根穷,報告還會根據(jù)構建變體、測試源代碼集和類路徑對依賴項進行分組导坟。下面是一個應用模塊的依賴項示例報告,其中按該模塊的調(diào)試構建變體的運行時類路徑和該模塊的插樁測試源代碼集的編譯類路徑對依賴項進行了分組惫周。
如需運行該任務,請按以下步驟操作:
- 依次選擇 View > Tool Windows > Gradle(或點擊工具窗口欄中的 Gradle 圖標)递递。
- 依次展開 AppName > Tasks > android喷橙,然后雙擊 androidDependencies。Gradle 執(zhí)行該任務后登舞,系統(tǒng)應該會打開 Run 窗口以顯示輸出。
顯示如下:
debugRuntimeClasspath - Dependencies for runtime/packaging
+--- :mylibrary (variant: debug)
+--- com.google.android.material:material:1.0.0@aar
+--- androidx.appcompat:appcompat:1.0.2@aar
+--- androidx.constraintlayout:constraintlayout:1.1.3@aar
+--- androidx.fragment:fragment:1.0.0@aar
+--- androidx.vectordrawable:vectordrawable-animated:1.0.0@aar
+--- androidx.recyclerview:recyclerview:1.0.0@aar
+--- androidx.legacy:legacy-support-core-ui:1.0.0@aar
...
debugAndroidTest
debugAndroidTestCompileClasspath - Dependencies for compilation
+--- androidx.test.ext:junit:1.1.0@aar
+--- androidx.test.espresso:espresso-core:3.1.1@aar
+--- androidx.test:runner:1.1.1@aar
+--- junit:junit:4.12@jar
...
六疙剑、修復依賴項解析錯誤
當您向應用項目添加多個依賴項時,這些直接和傳遞依賴項可能會相互沖突言缤。Android Gradle 插件會嘗試妥善解決這些沖突,但有些沖突可能會導致編譯時或運行時錯誤轿曙。
為幫助您調(diào)查是哪些依賴項導致了錯誤,請如上檢查您的應用的依賴項樹导帝,從中查找多次出現(xiàn)的依賴項或版本沖突的依賴項皮璧。
如果無法輕松識別重復的依賴項,請嘗試使用 Android Studio 的界面搜索包含重復類的依賴項悴务,具體操作步驟如下:
- 從菜單欄中依次選擇 Navigate > Class。
- 在彈出式搜索對話框中羡疗,確保已勾選 Include non-project items 旁邊的框。
- 輸入出現(xiàn)在構建錯誤中的類的名稱叨恨。
- 檢查結(jié)果以查找包含該類的依賴項挖垛。
下面幾部分介紹您可能會遇到的不同類型的依賴項解析錯誤及其修復方法。
1.修復重復類錯誤
如果某個類多次出現(xiàn)在運行時類路徑上痢毒,您會收到一條與以下內(nèi)容類似的錯誤:
Program type already present com.example.MyClass
此錯誤通常是下列其中一種情況所致:
-
二進制文件依賴項包含一個庫,該庫也作為直接依賴項包含在您的應用中栋荸。例如,您的應用聲明直接依賴于庫 A 和庫 B凭舶,但庫 A 已在其二進制文件中包含庫 B晌块。
- 如需解決此問題,請取消將庫 B 作為直接依賴項匆背。
-
您的應用的本地二進制文件依賴項和遠程二進制文件依賴項是同一個庫身冀。
- 如需解決此問題蜂大,請移除其中一個二進制文件依賴項蝶怔。
2.解決類路徑之間的沖突
當 Gradle 解析編譯類路徑時,會先解析運行時類路徑踢星,然后使用所得結(jié)果確定應添加到編譯類路徑的依賴項版本澳叉。換句話說沐悦,運行時類路徑?jīng)Q定了下游類路徑上完全相同的依賴項所需的版本號。
應用的運行時類路徑還決定了 Gradle 需要對應用的測試 APK 的運行時類路徑中的匹配依賴項使用的版本號瓶殃。圖 1 說明了類路徑的層次結(jié)構副签。
例如,當應用使用 implementation 依賴項配置加入某個依賴項的一個版本冠场,而庫模塊使用 runtimeOnly 配置加入該依賴項的另一個版本時本砰,就可能會發(fā)生多個類路徑中出現(xiàn)同一依賴項的不同版本的沖突。
在解析對運行時和編譯時類路徑的依賴關系時点额,Android Gradle 插件 3.3.0 及更高版本會嘗試自動解決某些下游版本沖突。例如载慈,如果運行時類路徑包含庫 A 版本 2.0诱贿,而編譯類路徑包含庫 A 版本 1.0咕缎,則插件會自動將對編譯類路徑的依賴關系更新為庫 A 版本 2.0,以避免錯誤焙蹭。
不過嫂伞,如果運行時類路徑包含庫 A 版本 1.0拯钻,而編譯類路徑包含庫 A 版本 2.0撰豺,插件不會將對編譯類路徑的依賴關系降級為庫 A 版本 1.0,您仍會收到一條與以下內(nèi)容類似的錯誤:
Conflict with dependency 'com.example.library:some-lib:2.0' in project 'my-library'.
Resolved versions for runtime classpath (1.0) and compile classpath (2.0) differ.
如需解決此問題污桦,請執(zhí)行以下某項操作:
- 將所需版本的依賴項作為 api 依賴項添加到庫模塊凡橱。也就是說,只有庫模塊聲明相應依賴項稼钩,但應用模塊也能以傳遞方式訪問其 API。
- 或者静秆,您也可以同時在兩個模塊中聲明相應依賴項绍载,但應確保每個模塊使用的版本相同。不妨考慮配置項目全局屬性击儡,以確保每個依賴項的版本在整個項目中保持一致。