自從將 Android 開發工具從 eclipse 遷移到 AndroidStudio 中以後,Android 工程構建愈來愈方便。見過不少項目中各式各樣的 Gradle 配置語法,懵懵懂懂。遂花費近兩週時間將官方文檔通讀一遍並整理出經常使用 Gradle 配置 Demo,以此博客做爲說明。java
一個最新版本的 AndroidStudio 毋庸置疑。下載地址:請戳。此處使用 3.5
版本。android
Gradle 版本 5.4.1
,無須單獨下載,在工程中配置好便可。git
軟件工程中,一般採用模塊化開發的策略,將一個項目劃分紅若干部分,多人協做開發中,每人完成一部分,最終完成整個項目。所以 AndroidStudio 也採用模塊化管理的方式編譯 Android 工程 。各個模塊之間的依賴關係相似於樹形結構,主 Module 做爲根節點,其他多個庫 Module 都直接或簡介的被主 Module 引用。github
基於前面的描述,Project 即 AndroidStudio 打開的一個目錄,其中包含 N+1 個 Module ,經過 Gradle 構建多個 Module 並最終合併成一個 apk 文件。web
其實,在一個 Project 目錄中,能夠有多個主 Module ,每一個主 Module 能夠依賴相同的庫 Module 並負責生成一個 apk 文件。一般不建議這麼使用,由於這樣會破壞 Module 之間的樹形依賴關係,不利於後期維護。推薦將複用頻率較高的庫 Module 封裝成 aar 文件,經過直接依賴或遠程依賴的方式用於不一樣的主 Module 之中。api
經過直譯的方式 ,能夠理解成 構建類型 和 產品特性 。構建類型中,默認包含 debug 和 release 兩種類型。一些基本的差別如 :debug 包容許調試,release 包不容許調試。產品特性能夠根據實際須要自行定義,如:收費和免費版本,漢語、英語及日語。不一樣的特性之間經過維度的概念區分。數組
最終如上圖所示,生成 2x3x2 共 12 種不一樣的 apk 文件。緩存
精簡後的 AndroidStudio 工程結構以下:bash
├── app
│ ├── build.gradle
│ ├── proguard-project.txt
│ └── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ └── flueky
│ │ └── demo
│ │ └── MainActivity.java
│ └── res
│ ├── layout
│ │ └── activity_main.xml
│ └── values
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
複製代碼
settings.gradle 示例:app
// 主Module
include ':app'
// 庫Module
include ':library'
// 添加外部庫
include 'other-lib'
project(':other-lib').projectDir = new File(rootDir, "../other-sample/library")
複製代碼
buildscript {
repositories {
// 倉庫地址
google()
jcenter()
mavenCentral()
}
// 工程的依賴配置
dependencies {
// 必須包含的 gradle 版本的構建工具。
classpath 'com.android.tools.build:gradle:3.4.1'
}
}
複製代碼
// 所有工程配置,做用於每一個 Module
allprojects {
repositories {
// 倉庫地址
google()
jcenter()
mavenCentral()
// 依賴倉庫,添加用於查找依賴項的目錄,能夠多個。
flatDir {
// jar、aar 存放的目錄
dirs 'libs'
}
}
}
複製代碼
// 擴展變量,用於統一管理每一個 Module 的有關配置
ext {
// 應用 id
applicationId = "com.flueky.demo"
// 統一控制各個 Module 使用的 SDK 版本
compileSdkVersion = 29
buildToolsVersion = "29.0.0"
minSdkVersion = 19
targetSdkVersion = 29
// 定義 Module 的版本號
app = [
versionCode: 1,
versionName: '1.0.0'
]
}
複製代碼
// 加載其餘的 gradle 配置文件,可選
apply from: "config.gradle"
複製代碼
// 聲明 Module 是主 Module,生成 apk 文件
apply plugin: 'com.android.application'
// 聲明 Module 是庫 Module,生成 aar 文件
apply plugin: 'com.android.library'
// 聲明 Module 是 Java 庫,生成 jar 文件
apply plugin: 'java-library'
複製代碼
還有不少 Plugin 能夠用,如: java
web
maven-publish
等。
另外一種寫法,一個 Module 中使用多個插件,如:
plugins {
id 'java'
id 'war'
id 'maven-publish'
}
複製代碼
android {
// 定義編譯的 sdk 版本,只有使用最新版本的sdk,才能在代碼中只用最新的 api 方法
compileSdkVersion rootProject.ext.compileSdkVersion
// 定義構建工具的版本
buildToolsVersion rootProject.ext.buildToolsVersion
}
複製代碼
rootProject.ext 是在 Project 的 build.gradle 文件中聲明。
android{
defaultConfig {
// 應用 id
applicationId rootProject.ext.applicationId
// 最小 sdk 版本,低於此 Android 版本的手機不能安裝
minSdkVersion rootProject.ext.minSdkVersion
// 目標 sdk 版本,低於此 Android 版本的手機完美兼容,高於此 Android 版本的手機,部分特性不能使用
// 升級 target 須要針對高版本作兼容。
targetSdkVersion rootProject.ext.targetSdkVersion
// 應用版本號,覆蓋安裝時,升級版本依據
versionCode rootProject.ext.app.versionCode
// 版本名稱,
versionName rootProject.ext.app.versionName
// 指定須要編譯 abi 版本的 so
ndk{
abiFilters 'armeabi-v7a'
}
// 設置編譯的資源
resConfigs "zh-rCN"
// 多 dex 支持 ,minSdkVersion >= 20 使用
multiDexEnabled true
}
}
複製代碼
簽名文件,至少配置一個。如未使用,debug 包,會使用 user home/.android/debug.keystore
的簽名文件。 release 包默認不簽名。
// 能夠將簽名文件信息配置在 keystore.properties 文件中
def ksPropFile = rootProject.file("keystore.properties")
def ksProp = new Properties()
// 加載簽名配置文件
ksProp.load(new FileInputStream(ksPropFile))
android{
signingConfigs {
// 生產簽名,讀取配置文件
release {
keyAlias ksProp['keyAlias']
keyPassword ksProp['keyPassword']
storeFile file(ksProp['storeFile'])
storePassword ksProp['storePassword']
}
// 測試簽名,靜態配置
debug {
keyAlias 'flueky'
keyPassword 'android'
storeFile file('../demo.keystore')
storePassword 'android'
}
}
}
複製代碼
使用配置的好處是,將生產簽名文件信息保存在配置文件中,不添加到版本控制工具中,能夠有效防範簽名文件信息泄露,被他人使用。
針對簽名文件的校驗,會有專門的防篡改技術,防止應用被反編譯 apk 後二次打包。如簽名文件泄露,會構成很大威脅。
android{
buildTypes {
// 測試版本
debug {
// 容許 Java 代碼調試(默認容許)
debuggable true
// 容許 JNI 代碼調試(默認容許)
jniDebuggable true
// 簽名 信息
signingConfig signingConfigs.debug
// 版本名稱後綴
versionNameSuffix = '-beta'
// 應用 Id 後綴
applicationIdSuffix '.debug'
}
// 發行版本
release {
// 禁止 Java 代碼調試(默認禁止)
debuggable false
// 禁止 JNI 代碼調試 (默認禁止)
jniDebuggable false
signingConfig signingConfigs.release
// build/intermediates/proguard-files 目錄下存在三個混淆配置文件
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
// 容許代碼壓縮、混淆、優化,默認狀況下會使用 R8 壓縮
minifyEnabled true
// 容許資源壓縮,包括清理無用資源。在生成 apk 時,如需保留被刪除的圖片使用,keep.xml 聲明 。
shrinkResources true
// 配置須要放在主 dex 中的類
// multiDexKeepFile file('multidex-config.txt')
// 或者使用下面的配置,語法同 proguard file
// multiDexKeepProguard file('multidex-config.pro')
}
// 內部使用版本
inner {
// 使用 debug 的配置
initWith debug
applicationIdSuffix '.inner'
}
}
}
複製代碼
AndroidStudio 默認支持 debug 和 release 兩種類型。並有一些默認的配置。經常使用配置見上。
android{
// 定義兩種緯度
flavorDimensions 'stage', 'api'
productFlavors {
// 開發階段
dev {
dimension 'stage'
}
// 生產階段
pro {
dimension 'stage'
}
minApi21 {
dimension 'api'
minSdkVersion 21
}
minApi23 {
dimension 'api'
minSdkVersion 23
}
minApi26 {
dimension 'api'
minSdkVersion 26
}
}
}
複製代碼
產品特性和構建類型,不只僅是在構建的時候修改些配置,還能夠在 src 目錄下,定義同名的文件夾,存放 java 、res 、assets 和 AndroidManifest.xml 等。用於實現不一樣的業務邏輯,資源圖片等。
產品特性和構建類型能夠經過組合的方式生成多個 apk 文件。但在實際中可能不須要部分組合方式。忽略後,可加速編譯過程。
如,內部使用不須要生產階段的 apk 文件,配置以下:
android{
// 設置不須要生成 apk 的類型和特性
variantFilter { variant ->
// 將多個 flavor 組合轉成字符串數組
def names = variant.flavors*.name
// 獲取到 buildType 名稱
def type = variant.buildType.name
// 忽略部分不須要生成的 apk
if (names.contains('pro') && type.equals("inner")) {
setIgnore(true)
}
}
}
複製代碼
android{
splits {
// 注意和 nkd.abiFilters 的衝突
abi {
enable true
// 包含全部版本so 的apk 文件。此配置僅用於 abi 。
// density 中默認會生成包含全部資源的 apk
universalApk true
// 去除 x86 和 x86_64
exclude 'x86', 'x86_64'
}
// 注意和 resConfigs 的衝突
density {
enable true
reset()
include "xhdpi"
// compatibleScreens 'small', 'normal', 'large', 'xlarge'
}
}
}
複製代碼
universalApk 只用在 abi 的配置中。true 表示按照默認的方式將所有 so 打包 。density 中,此值必須爲 true。 使用 abi 和 density 要注意同 ndk.abiFilters 和 resConfigs 使用的衝突。
依賴第三方庫,在新版本 Gradle 中,經常使用的有 implementation
和 api
。
它們區別是:
這樣的好處是,若是隻修改了 Module C , 狀況 1 只會從新編譯 B 和 C ,狀況 2 會從新編譯 A B C 。 所以在實際應用中,避免大量使用 api
的方式。
下面列舉了對 jar 文件、 aar 文件和 maven 庫文件的依賴方式。
dependencies {
// 依賴同級的 libs 目錄,只包含jar
implementation fileTree(include: '*.jar', dir: 'libs')
// 依賴同級的 libs 目錄,包含 jar 和 aar,還能夠選擇不包含指定文件
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
// debug 類型的依賴
debugImplementation fileTree(include: '*.jar', dir: 'src/debug/libs')
// release 類型的依賴
releaseImplementation fileTree(include: '*.jar', dir: 'src/release/libs')
// 同理 devImplementation minApi21Implementation innerImplementation
// 若是 須要組合使用,如 devMinApi21DebugImplementation,見 configurations
// 依賴本地 module
implementation project(':library')
implementation project(':other-lib')
// 等同於帶 path 參數
// implementation project(path: ':library')
// 依賴遠程庫,不建議在版本號中使用 + 通配符,括號能夠省略
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation('com.android.support:support-v4:28.0.0') {
// 一個遠程庫可能包含多個第三方庫,能夠排除指定庫
exclude group: 'com.android.support', module: 'collections'
}
// 等同於複雜形勢
// implementation group: 'com.android.support', name: 'support-v4', version: '28.0.0'
implementation 'com.google.dagger:dagger:2.24'
annotationProcessor 'com.google.dagger:dagger-compiler:2.24'
// 5.0 以前多 dex 支持,minSdkVersion < 20 必須使用。
implementation 'androidx.multidex:multidex:2.0.1'
}
複製代碼
注意到上面的配置中存在 debugImplementation 和 releaseImplementation 。這是對不一樣構建類型單獨指定的依賴方式。
產品特性也可使用上面的配置,可是須要先聲明,方式以下:
configurations {
// 添加多個依賴項配置
devMinApi21DebugImplementation {}
devMinApi21Api {}
devDebugCompileOnly {}
minApi21DebugRuntimeOnly {}
}
複製代碼
篇幅有限 ,以上介紹均是經常使用配置。更多配置請見源碼。
關於 AndroidManifest.xml 合併衝突,有機會在後面的文章中講。
主 Module 有 inner 的構建類型,庫 Module 中、沒有 ,構建 app 時會報錯。
可在庫 Module 中添加 inner 的構建類型,或者在主 Module 的 inner 類型中,添加下面的配置。
// inner 匹配失敗 , debug 匹配成功, release 忽略
matchingFallbacks = ['inner', 'debug', 'release']
複製代碼
如需匹配 release 時,將 release 放在 debug 前,或者直接刪除 debug 。
主 Module 有的產品特性,庫 Module 中沒有,構建 app 時會報錯。
錯誤緣由同 問題 1
。如,庫 Module 中存在其餘相似的產品特性,可以使用匹配的方式 ,以下:
android{
productFlavor{
minApi21 {
minSdkVersion 21
// 庫 module 沒有 minApi21 ,匹配較高版本
// 同時須要在 AndroidManifest.xml 中使用 overrideLibrary
matchingFallbacks = ['minApi23']
}
minApi26 {
minSdkVersion 26
// 庫 module 沒有 minApi26 ,匹配較低版本,可兼容
matchingFallbacks = ['minApi23']
}
}
}
複製代碼
如,庫 Module 中沒有定義任何產品特性,能夠直接在 defauleConfig
中,忽略對維度的依賴 。
android{
defauleConfig{
// 庫 module 沒有開發進度的維度,所以忽略
missingDimensionStrategy 'dev', 'pro'
}
}
複製代碼
主 Module 的 minSdk 小於 庫 Module 的 minSdk。
使用 overrideLibrary ,指定複寫庫 Module 的 packageName 。
<manifest xmlns:tools="http://schemas.android.com/tools">
<!-- minSdkVersion 存在衝突的解決方案-->
<uses-sdk tools:overrideLibrary="com.flueky.library" />
</manifest>
複製代碼
源碼地址。
以爲有用?那打賞一個唄。去打賞