1. 程式人生 > 其它 >android studio gradle目錄_buildTypes——安卓gradle

android studio gradle目錄_buildTypes——安卓gradle

技術標籤:android studio gradle目錄

目錄
一、前言
二、buildTypes
三、buildType
1、buildTypes存在形式
2、buildTypes 中屬性的意義
3、buildTypes 中方法的意義
四、寫在最後

一、前言

繼上一篇部落格分享了defaultConfig 中可配置引數的含義,今天我們來分享另一個我們也很熟悉的buildTypes

二、buildTypes

buildTypes也是存在於每個應用級模組中的 android 下的,即如下所示,是每次構建完專案之後自動生成的結構。

android {
buildTypes{
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

buildTypes 可以配置我們需要的構建型別,例如我們常用到的 “測試型別” 和 “本地型別”,則可以使用如下配置

buildTypes{
// 釋出型別
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
// 測試型別,給測試人員
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
// 本地型別,和後端聯調使用
local {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

增加完這些配置後,我們可以在 android studio 看到多了 “debug” 和 “local” 兩個可以構建的型別,在 “點選執行” 時,便會使用我們所選擇的構建型別。假設此時選擇的是 “debug” 型別,我們此時執行程式碼,則是 debug 下的配置引數。

7dd992db-b030-eb11-8da9-e4434bdf6706.png

當然執行編譯成 apk 時,也不例外,各自使用的也是各自型別的配置。

而這裡所說的 “release”,“debug”,“local”,三個構建型別其實便是三個buildTypebuildType所能配置的引數便是我們今天要來捋清楚的。

三、buildType

buildType 官方文件

https://google.github.io/android-gradle-dsl/3.3/com.android.build.gradle.internal.dsl.BuildType.html

1、buildType存在形式

從上一篇部落格我們知道,每個配置最終會被對映為一個類,或是一個屬性、或一個方法。buildType也不例外,他會被對映為com.android.build.gradle.internal.dsl.BuildType,繼承結構如下

7ed992db-b030-eb11-8da9-e4434bdf6706.png

我們重新看一下 DefaultConfig 的繼承結構,可以看到都會繼承到BaseConfigImpl類,說明兩者會有一定的交集。這也說明了為什麼我們看 gradle 檔案時,總感覺一個配置引數哪裡都能出現的情況(後面會進行更多的比較,來解除我們這種疑惑)

7fd992db-b030-eb11-8da9-e4434bdf6706.png

2、buildType 中屬性的意義

我們先來一個約定,避免使用的程式碼過於冗長。

buildTypes{
debug {
// 我們下面的 “使用方法” 程式碼都是基於這一塊,除非特殊說明。
}
}

2.1 applicationIdSuffix

  • 型別:String

  • 描述:會追加在 applicationId 字串的後面,形成最終的包名。

  • 值得一提:在 defaultConfig 中也有這個屬性,但一般不會使用。而會在 buildTypes 中使用,這樣可以讓包名不同,同時安裝多個型別的應用。例如我們上面所提到的 release包、debug包、local包,都可以同時存在而不會覆蓋,方便除錯。

  • 使用方法:

debug {
applicationIdSuffix '.debug'
}

2.2 consumerProguardFiles

  • 型別:List< File >

  • 描述:這個屬性只作用於我們建立的library中,包括我們以aar形式匯入的 library ,或是直接建立的 library。它的作用是,負責該 library 被進行編譯時的混淆規則,我們在 主App 的模組下則可以不用再管理各個 library 的混淆規則,會直接使用各個 library 的混淆規則檔案。

  • 值得一提:這個屬性 和proguardFiles的區別在於,consumerProguardFiles會被 主App模組 作為混淆檔案使用匯入,而proguardFiles則不會。

  • 使用方法:

debug {
consumerProguardFiles 'consumer-rules.pro'
......省略其他配置
}

// 因為該屬性是一個 List 型別,如果需要多個檔案配置,則如下所示
debug {
consumerProguardFiles 'consumer-rules.pro','zincPower-rules.pro'
......省略其他配置
}

2.3 crunchPngs

  • 型別:boolean

  • 描述:是否對 PNG 圖片進行壓縮處理。設定為true時,會對未進行最佳壓縮的PNG資源進行壓縮,但也會增加構建時間。

  • 值得一提:預設情況下,release 型別是開啟的,debug 型別則為關閉。

  • 使用方法:

debug {
crunchPngs false
......省略其他配置
}

2.4 debuggable

  • 型別:boolean

  • 描述:是否可以對應用進行除錯。

  • 值得一提:release 的構建型別預設為不可除錯,即為false。而 debug 預設為true,既可以除錯。所謂的無法除錯即下圖的 “蟲子” 標記無法讓應用啟動,而正常的執行是可以的。

    80d992db-b030-eb11-8da9-e4434bdf6706.png
  • 使用方法:

debug {
debuggable true
}

2.5 javaCompileOptions

  • 型別:JavaCompileOptions

  • 描述:配置編譯時 java 的一些引數,例如我們使用annotationProcessor時所需要的引數。

  • 使用方法:

debug {
javaCompileOptions {
annotationProcessorOptions{
arguments = []
classNames ''
....
}
}
......省略其他配置
}

JavaCompileOptions 可以配置的具體引數,請進

https://google.github.io/android-gradle-dsl/3.3/com.android.build.gradle.internal.dsl.JavaCompileOptions.html

2.6 jniDebuggable

  • 型別:boolean

  • 描述:是否可以對應用的 native 程式碼進行除錯

  • 值得一提:release 的構建型別預設為不可除錯 native 程式碼,即為false。而 debug 預設為true,既可以除錯 native 程式碼。無法對 native 程式碼除錯,指的是即使在native方法打了斷點,程式碼也不會被 “停住”。

  • 使用方法:

debug {
jniDebuggable true
}

2.7 manifestPlaceholders

  • 型別:Map

  • 描述:配置可以在AndroidManifest.xml中使用的引數。

  • 使用方法:這裡想配置我們應用的 logo 為測試版本的logo,方便測試人員區分不同型別的包,則可以在 gradle 中使用下面這段

debug {
manifestPlaceholders = [APP_LOGO_ICON: "@mipmap/ic_logo"]
}

然後在AndroidManifest.xml中使用,使用${你配置的變數名}

// 在 application 中使用替換,還需要多新增 tools:replace 這一標籤,將我們需要替換的名稱寫上,例如這裡的 android:icon
<applicationandroid:allowBackup="true"android:icon="${APP_LOGO_ICON}"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/AppTheme"tools:replace="android:icon">
......

2.8 minifyEnabled

  • 型別:boolean

  • 描述:是否開啟混淆,程式碼優化。true開始,false則關閉。

  • 使用方法:

debug {
minifyEnabled true
}

2.9 proguardFiles

  • 型別:List< File >

  • 描述:配置混淆規則檔案,只有minifyEnabled設定為 true 的時候會使用這個引數,檔案中需要申明哪些檔案不被優化和混淆。

  • 值得一提:因為被混淆後端程式碼,類名和方法名都會有所變化,所以進行反射會失敗,這是我們就需要進行申明他們不被混淆。(這裡只是舉了使用這個引數的一個場景,如果應用本來是正常的,開了混淆後,出現了莫名奇妙的bug,那就思考下是否因為混淆導致了這一bug)

  • 使用方法:

debug {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}

2.10 multiDexEnabled

64K 引用限制問題官方文件

https://developer.android.com/studio/build/multidex

  • 型別:Boolean

  • 描述:是否開啟分包。因為安卓中方法索引值為兩個位元組,四位十六進位制的一個數值,即[0, 0xffff],所以最大方法數為65536個。一旦超出了,就需要進行分包,所以我們就需要開啟這個引數。

  • 使用方法:

android{
buildTypes {
debug {
multiDexEnabled true
...
}
}
}

// 新增依賴
dependencies {
// 如果使用的為 AndroidX,則使用下面這個匯入
// implementation 'androidx.multidex:multidex:2.0.1'
// 如果不使用 AndroidX,則使用下面這段
compile 'com.android.support:multidex:1.0.3'
}

有兩種開啟 MultiDex 方法:

// 第一種:讓你應用的 Application 繼承 MultiDexApplication。
public class MyApplication extends MultiDexApplication {

}

// 第二種:重寫應用的 Application 方法 attachBaseContext
public class MyApplication extends Application {

@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}

最後別忘了在AndroidManifest.xml中使用我們在上面的 Application。

2.11 multiDexKeepFile

  • 型別:File

  • 描述:將我們需要的類打包進主包,即classs.dex。我們在第 2.10 小點,分享到使用了多包處理,有時我們需要將一些主要的類打包進主包,則可以使用該屬性。

  • 使用方法:

debug {
multiDexKeepFile file('multidex-config.txt')
...
}

multidex-config.txt 中的書寫則如下,每一個檔案則為一行

com/example/MyClass.class
com/example/TestClass.class

2.12 multiDexKeepProguard

  • 型別:File

  • 描述:將我們需要的類打包進主包,和第 2.11 點的功能相同,區別在於寫法。

  • 使用方法:

debug {
multiDexKeepFile file('multidex-config.pro')
...
}

multidex-config.pro 中的寫法如下

// 將會保留所有的在com.example package的類
-keep class com.example.** { *; }

2.13 name

  • 型別:String

  • 描述:構建型別的名字。

  • 使用方法:

// debug 則會被賦值至 name 屬性,而且 name 是final 型別,無法在改動。
debug{
...
}

2.14 pseudoLocalesEnabled

  • 型別:boolean

  • 描述:這個屬性用於開啟偽語言,用於發現UI中潛在的可本地化問題。

  • 使用方法:

第一步:我們在配置中開啟該屬性

debug{
pseudoLocalesEnabled true
}

第二步:安裝我們的應用 第三步:開啟設定 -> 系統 -> 語言和輸入法 -> 語言 -> 新增語言

會在 “新增語言” 頁面中看到如下圖的選項,選擇圖中紅色框的內容,各自的不同在圖中也有標明,我們往下走看看具體不同的表現是什麼。

小盆友的測試機是 榮耀8,不同機子會有些許不同

82d992db-b030-eb11-8da9-e4434bdf6706.png

選擇之後,選擇不同的語言會有不同效果,如圖所示

(1)左邊為未開啟時的樣子;

(2)中間為選擇了Pseudo locale(相當於en-XA);

(3)右邊為選擇了Bidirection test locale(相當於en-XB);

83d992db-b030-eb11-8da9-e4434bdf6706.png

2.15 renderscriptDebuggable

  • 型別:boolean

  • 描述:是否可以對 renderscript 程式碼進行除錯

  • 使用方法:

debug {
renderscriptDebuggable true
}

2.16 renderscriptOptimLevel

  • 型別:int

  • 描述:設定渲染指令碼等級

  • 使用方法:

debug {
renderscriptOptimLevel 3
}

2.17 shrinkResources

shrinkResources 官方使用手冊

https://developer.android.com/studio/build/shrink-code?utm_source=android-studio#shrink-resources

  • 型別:boolean

  • 描述:是否壓縮資源,如果開啟,gradle在編譯時幫我們把沒有使用的資源給移除。

  • 值得一提:shrinkResources 的開啟需要 minifyEnabled 也為開啟狀態,否則無法執行。

  • 使用方法:

debug {
shrinkResources false
}

開啟後編譯完會看到如下日誌

85d992db-b030-eb11-8da9-e4434bdf6706.png

2.18 signingConfig

  • 型別:SigningConfig

    SigningConfig 的可配置引數:https://google.github.io/android-gradle-dsl/3.3/com.android.build.gradle.internal.dsl.SigningConfig.html

  • 描述:配置簽名配置。apk包能被安裝是需要被簽名的,我們直接執行的時候,是使用了系統預設的簽名證書,當我們要釋出release包時,則需要使用屬於個人或企業的簽名。

  • 使用方法:

buildTypes {
release {
signingConfig {
// 不建議將簽名證書的資訊寫在這裡,而應該是寫在 properties 檔案中,將其引入使用
config {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
...
}
}

2.19 testCoverageEnabled

  • 型別:boolean

  • 描述:測試覆蓋率,可以獲取測試覆蓋率的報告

  • 值得一提:記得將 minifyEnabled 置為 false,否則報告也會是以混淆後的類名出現。

  • 使用方法:

第一步:在 build.gradle 中開啟 testCoverageEnabled

debug {
testCoverageEnabled true
}

第二步:連線上一臺可用裝置,因為我們執行的測試程式碼是要基於裝置的,如果不連線,測試階段會報如下錯

86d992db-b030-eb11-8da9-e4434bdf6706.png

第三步:在 android studio 的 終端(即 Terminal)中輸入下面這行命令,檢視所有可執行任務。

小盆友是 mac 環境,所以 ./gradlew 開頭。windows 的環境則直接使用 gradlew 即可。

./gradlew app:tasks

輸入執行後,可以看到圖中高亮部分的可執行task。

88d992db-b030-eb11-8da9-e4434bdf6706.png

我們以駝峰式(即第一個字母加上後面每個單詞的首字母且以大寫的形式)將其執行,程式碼如下

// create + 你的構建型別名(這裡為debug) + CoverReport
./gradlew app:cDCR

執行完之後,就是檢視測試報告的階段了。我們進入coverage目錄,具體路徑如下圖所示。

8ad992db-b030-eb11-8da9-e4434bdf6706.png

最後用瀏覽器開啟 index.html 檔案,就可以看報告啦,如下圖所示,因為小盆友的這個專案沒有寫測試程式碼,所以覆蓋率為0。

8ed992db-b030-eb11-8da9-e4434bdf6706.png

2.20 useProguard

  • 型別:boolean

  • 描述:是否開啟總是開啟 proguard

  • 使用方法:

debug {
useProguard true
}

2.21 versionNameSuffix

  • 型別:String

  • 描述:追加在 versionName 之後

  • 使用方法:

debug {
// 如果 versionName "1.0.0" ,則最終的版本名為 1.0.0.test
versionNameSuffix ".test"
.....
}

2.22 zipAlignEnabled

  • 型別:boolean

  • 描述:是否開啟zipAlign。會對應用程式進行位元組對齊,對齊後會減少了執行應用程式時消耗的記憶體。

  • 使用方法:

debug {
zipAlignEnabled true
.....
}

2.23 matchingFallbacks

  • 型別:List< String >

  • 描述:用於處理 本地依賴library 間 BuildType 的衝突。

    matchingFallbacks 還可以處理 維度風味的 問題,但我們這裡先不討論,後續的文章會介紹。

  • 使用方法:

一個東西的出現是為了處理至少一個問題,所以我們需要先了解下這個問題是怎麼產生的。

8fd992db-b030-eb11-8da9-e4434bdf6706.png

如上圖所示,我們的 主Module(一般是App),存在了三個構建型別,即我們一開始所提的 “release”、“debug”、“local” 三種。

此時我們在專案添加了一個 module 名字為 library,並依賴進我們的app中。當我們構建 “release”、“debug” 兩種版本時,都不會有任何問題,因為 library 預設也提供了 “release”、“debug” 兩種構建版本。

但是當我們使用 “local” 時,便會出問題了,因為此時 gradle 的指令碼也會預設選擇 “library” 的 “local”,但 “library” 中並沒有。會報下面這樣的錯誤

ERROR: Unable to resolve dependency for ':[email protected]/compileClasspath': Could not resolve project :lib:library.
Show Details
Affected Modules: app

此時就需要幫 “local” 從 “library” 中選擇一個可用的構建型別,則是通過matchingFallbacks進行設定。

鋪墊了這麼多,接下來就是怎麼使用了,在 app 的 build.gradle 中新增如下程式碼即可。

local{
matchingFallbacks = ['zinc','release']
...
}

值得一提的是,我們可以配置多個,gradle在編譯的時候,會按照從頭開始匹配的原則,例如這裡的 “zinc” 會匹配不到,則匹配 “release”,因為 “release” 匹配到了,則會進行使用,中斷後面的匹配。

3、buildTypes 中方法的意義

3.1 buildConfigField(type, name, value)

  • 描述:我們可以在 BuildConfig 類中新增值,最終會在 BuildConfig 中新增如下一行程式碼。

// 值的注意的是 value 的值是原樣放置,我們通過使用方法一節來了解
=
  • 使用方法:

debug {
// 可以通過 BuildConfig 進行獲取
buildConfigField('String', 'name', '"zinc"')
buildConfigField('int', 'age', '26')
.....
}

最終會生成如下圖的配置,我們可以通過下面程式碼進行獲取

String name = BuildConfig.name;
int age = BuildConfig.age;
91d992db-b030-eb11-8da9-e4434bdf6706.png

值的一提的是,我們設定 String 型別的引數時,需要加上 "" 雙引號(如例子中的name屬性)。切記!

3.2 consumerProguardFile(proguardFile)

  • 描述:和上面分享的 2.2 小點的屬性 consumerProguardFiles 是一樣的作用。只是這裡只能設定一個 混淆檔案。

  • 使用方法:

debug {
consumerProguardFile('consumer-rules.pro')
}

3.3 consumerProguardFiles(proguardFiles)

  • 描述:和上面分享的 2.2 小點的屬性 consumerProguardFiles 是一樣的作用,而且也是多個混淆檔案。

  • 使用方法:

debug {
consumerProguardFile('consumer-rules.pro', 'zincPower-rules.pro',.....)
}

3.4 externalNativeBuild(action)

  • 型別:ExternalNativeBuildOptions

  • 描述:這裡我們設定 ndk 編譯過程的一些引數。分為 cmake 和 ndkBuild 兩個引數。

  • 使用方法:

debug {
externalNativeBuild {
ndkBuild {
// Passes an optional argument to ndk-build.
arguments "NDK_MODULE_PATH+=../../third_party/modules"
}
// For ndk-build, instead use the ndkBuild block.
cmake {
// Passes optional arguments to CMake.
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"

// Sets a flag to enable format macro constants for the C compiler.
cFlags "-D__STDC_FORMAT_MACROS"

// Sets optional flags for the C++ compiler.
cppFlags "-fexceptions", "-frtti"

// Specifies the library and executable targets from your CMake project
// that Gradle should build.
targets "libexample-one", "my-executible-demo"
}
}
}

cmake 具體引數文件:

https://google.github.io/android-gradle-dsl/3.3/com.android.build.gradle.internal.dsl.ExternalNativeCmakeOptions.html

ndkBuild 具體引數文件:

https://google.github.io/android-gradle-dsl/3.3/com.android.build.gradle.internal.dsl.ExternalNativeNdkBuildOptions.html

3.5 initWith(that)

  • 描述:會拷貝給定的 buildType(即引數的值)

  • 使用方法:

buildTypes {
debug{
}
local{
// 會拷貝 debug 的配置
initWith debug{
// 在這裡進行我們自己的配置
}
}
}

3.6 proguardFile(proguardFile)

  • 描述:新增混淆檔案,和 2.9小點 的功能一致,只是傳入的是一個檔案,這裡就不再贅述

  • 使用方法:

 debug {
proguardFile 'proguard-rules.pro'
}

3.7 proguardFiles(files)

  • 描述:新增混淆檔案,和 2.9小點 的功能一致,這裡就不再贅述

  • 使用方法:

debug {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}

3.8 setProguardFiles(proguardFileIterable)

  • 描述:新增混淆檔案,和 2.9小點 的功能一致,只是寫法稍微不同,這裡就不再贅述

  • 使用方法:

debug {
proguardFiles = [getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro']
}

3.9 resValue(type, name, value)

  • 描述:新增 value 資源

  • 使用用法:

debug {
// 新增至 res/value,通過 R.string.age 獲取
resValue('string', 'age', '12 years old')
}

四、寫在最後

Gradle 的配置檔案看起來好像挺亂,其實是因為我們沒有進行整體的梳理。很多配置其實不是沒有用,而是我們沒有對他有一個整體的瞭解,正所謂“無知最可怕”。

如果喜歡的話請給我一個贊,並關注我吧。文章中如有寫的不妥的地方,請評論區與我討論吧,共同進步。

專案地址:https://github.com/zincPower/GradleStudy

95d992db-b030-eb11-8da9-e4434bdf6706.png