Gradle基礎(chǔ)
Gradle的生命周期分為三個(gè)不同的階段:初始化 -》 配置 -》 構(gòu)建
初始化:settings.gradle
配置:build.gradle
構(gòu)建:gradle
初始化階段會(huì)讀取根目錄下setting.gradle的include信息,決定哪些工程會(huì)加入構(gòu)建過程,并且創(chuàng)建project實(shí)例。
配置階段會(huì)按引用樹去執(zhí)行所有工程的build.gradle腳本,配置project對(duì)象,一個(gè)對(duì)象由多個(gè)任務(wù)組成。
運(yùn)行階段會(huì)根據(jù)Gradle命令傳遞過來的Task名稱,執(zhí)行相關(guān)依賴任務(wù)。
版本參數(shù)優(yōu)化
每個(gè)module的build.gradle文件都擁有一些必要的屬性,同一個(gè)Android工程中,在不同的模塊中要求這些屬性一致,如果不一致會(huì)造成資源 的重復(fù),另一方面會(huì)降低編譯效率。那么就必須有一個(gè)統(tǒng)一的、基礎(chǔ)的gradle配置。
資源引用配置
1 使用sourceSets的方式來指定文件的路徑。
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
}
2 可以動(dòng)態(tài)添加res資源,在buildtype 和productFlavor中定義resValue變量
resValue "string","app_name","xxx"
resValue只能動(dòng)態(tài)添加資源,無法替換資源。如果資源名重復(fù),Gradle會(huì)提示重復(fù)定義資源。
3可以指定特定尺寸的資源
resConfigs "hdpi","xhdpi","xxhdpi"
4 通過build.gradle編譯生成BuildConfig文件,可以直接讓代碼讀取到BuildConfig中的值。
buildConfigField("String","BASE_URL","\"https://xxx.com.cn\"")
在buildConfig文件中就會(huì)得到:
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 10101;
public static final String VERSION_NAME = "1.01.01";
// Fields from build type: debug
public static final String BASE_URL = "https://xxx.com.cn";
}
Gradle加載的優(yōu)先級(jí)
BuildType -> productFlavor -> Main -> dependencies
最左邊的優(yōu)先級(jí)越高
Build types
Gradle在Android中的build type是用來處理app或者library應(yīng)該被構(gòu)建成什么類型,在這個(gè)配置中,我們可以定義應(yīng)用的包名是什么,是否自動(dòng)去除掉沒有引用的資源,是否開啟混淆等等。
buildTypes {
release {
//設(shè)置正式包名稱
applicationVariants.all { variant ->
variant.outputs.all { output ->
project.ext { appName = 'xxx' }
def newName = project.ext.appName +"-" + defaultConfig.versionName + "-" +buildTime() + ".apk"
outputFileName = new File(newName)
}
}
//開啟混淆
minifyEnabled true
//Zipalign優(yōu)化
zipAlignEnabled true
//移除無用的resource文件
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
minifyEnabled false
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
applicationVariants.all { variant ->
variant.outputs.all { output ->
project.ext { appName = 'XXX' }
def newName = project.ext.appName +"-" + defaultConfig.versionName + "-" +buildTime() + ".apk"
outputFileName = new File(newName)
}
}
}
Product flavors
與build type相反,build type用來構(gòu)建不同類型的app,debug版或release版,而produc flavors則是用來在同一個(gè)app上創(chuàng)建不同的版本,如付費(fèi)版和免費(fèi)版。一個(gè)非常常見的應(yīng)用場(chǎng)景就是我們創(chuàng)建了一個(gè)銀行管理的app給不同銀行提供服務(wù),但是不同的銀行App的logo不一樣,有produc flavors就能在基于一套代碼上創(chuàng)建不同版本的app或者library。
productFlavors {
red {
applicationId 'com.gradleforandroid.red'
versionCode 3
}
blue {
applicationId 'com.gradleforandroid.blue'
minSdkVersion 14
versionCode 4
}
}
Multiflavor variants
在某些情況下,我們可能需要進(jìn)行flavors的組合,比方說你的app有兩套主題,綠色主題和紅色主題,然后有兩個(gè)版本,付費(fèi)版和免費(fèi)版,你可能需要進(jìn)行組合,類似于紅色免費(fèi)版,紅色付費(fèi)版,綠色免費(fèi)版,綠色付費(fèi)版。通過使用flavorDimensions可以解決flavors組合的問題,
flavorDimensions "color", "price"
productFlavors {
red {
flavorDimension "color"
}
blue {
flavorDimension "color"
}
free {
flavorDimension "price"
}
paid {
flavorDimension "price"
}
}
Variant filters
在某些情況下,可能我們不想使用某種build variant,例如現(xiàn)在有debug和release的build type,red和blue的flavors,但是,blue還是測(cè)試環(huán)境根本現(xiàn)在用不到blue的release版本,那么我們可以直接過濾掉,在android studio中的buildVariants窗口就不會(huì)出現(xiàn)了,過濾可以在app模塊或者library模塊的build.gradle文件中加入如下代碼:
android.variantFilter { variant ->
if (variant.buildType.name.equals('release')) {
variant.getFlavors().each() { flavor ->
if (flavor.name.equals('blue')) {
variant.setIgnore(true);
}
}
}
}
gradle的依賴特性
1 implementation
會(huì)將指定的依賴添加到編譯路徑,并且會(huì)將該依賴打包到輸出,如apk中,但是這個(gè)依賴在編譯時(shí)不能暴露給其他模塊,例如依賴此模塊的其他模塊。這種方式指定的依賴在編譯時(shí)只能在當(dāng)前模塊中訪問。
例如:
有兩個(gè)模塊app 和test,模塊app依賴test,test添加了遠(yuǎn)程二進(jìn)制庫依賴joda-time,在test模塊中使用沒有問題,在app模塊中使用則報(bào)錯(cuò)。
2 api
使用api配置的依賴會(huì)將對(duì)應(yīng)的依賴添加到編譯路徑,并將依賴打包輸出,但是這個(gè)依賴是可以傳遞的,比如模塊A依賴模塊B,B依賴庫C,模塊B在編譯時(shí)能夠訪問到庫C,但是與implemetation不同的是,在模塊A中庫C也是可以訪問的。
3 compileOnly
compileOnly修飾的依賴會(huì)添加到編譯路徑中,但是不會(huì)打包到apk中,因此只能在編譯時(shí)訪問,且compileOnly修飾的依賴不會(huì)傳遞
4 runtimeOnly
這個(gè)與compileOnly相反,它修飾的依賴不會(huì)添加到編譯路徑中,但是被打包到apk中,運(yùn)行時(shí)使用。
5 annotationProcessor
用于注解處理器的依賴配置,像第三方庫 ButterKnife
Gradle的一些配置
開啟Gradle的守護(hù)進(jìn)程來構(gòu)建項(xiàng)目:
org.gradle.daemon=true
如果你要構(gòu)建一個(gè)多Module并且依賴關(guān)系比較復(fù)雜的項(xiàng)目,那么你可以使用并行項(xiàng)目執(zhí)行:
org.gradle.parallel=true
在Gradle主目錄中配置的屬性優(yōu)先級(jí)高于在項(xiàng)目中配置的屬性。當(dāng)你并不想一個(gè)個(gè)項(xiàng)目的去改動(dòng)配置時(shí),可以定義一份常用的Gradle配置文件放在Gradle的主目錄下
對(duì)于內(nèi)存較小的機(jī)器避免Gradle編譯卡頓
修改gradle.properties,避免影響其它人編譯速度,把修改的gradle.properties文件放到用戶文件夾.gradle下
#設(shè)置最大堆內(nèi)存為1.5g和最大非堆內(nèi)存0.5g
org.gradle.jvmargs=-Xmx1536m -XX\:MaxPermSize\=512m -XX\:+HeapDumpOnOutOfMemoryError -Dfile.encoding\=UTF-8
#不啟用守護(hù)進(jìn)程
org.gradle.daemon=false
#不啟用并行編譯
org.gradle.parallel=false
#使用構(gòu)建緩存
android.enableBuildCache=true
修改build.gradle文件,如下:
dexOptions {
//最大堆內(nèi)存
javaMaxHeapSize "2g" // 1g should be also OK
}
壓縮Apk大小
加快Build速度
Gradle的Android插件在 buildType 上有一個(gè)名為 minifyEnabled 的布爾屬性,我們需要將其設(shè)置為true以啟用ProGuard:
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
壓縮Resource文件
自動(dòng)壓縮的方式很簡(jiǎn)單,就是在構(gòu)建中配置 shrinkResources 屬性。如果將此屬性設(shè)置為true,Android構(gòu)建工具將自動(dòng)檢測(cè)哪些資源未被使用,并且不會(huì)將它們包括在APK中。
android {
buildTypes {
release {
minifyEnabled = true
shrinkResources = true
}
}
}
使用 resConfigs 屬性配置要保留的資源,然后其余的將被拋出。
defaultConfig {
resConfigs "en", "da", "nl"
resConfigs "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
}
忽略Lint檢查
當(dāng)使用Gradle執(zhí)行構(gòu)建時(shí),Android構(gòu)建任務(wù)將會(huì)對(duì)代碼執(zhí)行Lint檢查。Lint是一個(gè)靜態(tài)代碼分析工具,用于標(biāo)記布局和Java代碼中的潛在錯(cuò)誤。在某些情況下,Lint一旦報(bào)錯(cuò),構(gòu)建就會(huì)停止。如果之前沒有在項(xiàng)目中使用Lint,并且我們想遷移到Gradle,Lint可能會(huì)出現(xiàn)很多錯(cuò)誤。為了使構(gòu)建工作不會(huì)因?yàn)長int檢查而中斷,你可以配置Gradle來忽略Lint錯(cuò)誤,并通過禁用 abortOnError 來阻止它們中止構(gòu)建。這只是一個(gè)臨時(shí)解決方案,因?yàn)楹雎訪int檢查可能會(huì)產(chǎn)生像丟失翻譯類似這樣的潛在錯(cuò)誤,這可能會(huì)導(dǎo)致應(yīng)用程序崩潰的問題。為了防止Lint阻塞構(gòu)建過程,可以像下面這樣禁用abortOnError:
android {
lintOptions {
abortOnError false
}
}