Android Gradle使用總結
其他
Android Gradle
Android專案使用 Gradle 作為構建框架,Gradle 又是以Groovy為指令碼語言。所以學習Gradle之前需要先熟悉Groovy指令碼語言。
Groovy是基於Java語言的指令碼語言,所以它的語法和Java非常相似,但是具有比java更好的靈活性。下面就列舉一些和Java的主要區別。
Android Gradle 的 Project 和 Tasks
這個Gradle中最重要的兩個概念。每次構建(build)至少由一個project構成,一個project 由一到多個task構成。專案結構中的每個build.gradle檔案代表一個project,在這編譯指令碼檔案中可以定義一系列的task;task 本質上又是由一組被順序執行的Action`物件構成,Action其實是一段程式碼塊,類似於Java中的方法。
Android Gradle 構建生命週期
每次構建的執行本質上執行一系列的Task。某些Task可能依賴其他Task。哪些沒有依賴的Task總會被最先執行,而且每個Task只會被執行一遍。每次構建的依賴關係是在構建的配置階段確定的。每次構建分為3個階段:
- Initialization: 初始化階段
這是建立Project階段,構建工具根據每個build.gradle檔案創建出一個Project例項。初始化階段會執行專案根目錄下的settings.gradle檔案,來分析哪些專案參與構建。
所以這個檔案裡面的內容經常是:
include ':app'
include ':libraries:someProject'
這是告訴Gradle這些專案需要編譯,所以我們引入一些開源的專案的時候,需要在這裡填上對應的專案名稱,來告訴Gradle這些專案需要參與構建。
- Configuration:配置階段
這個階段,通過執行構建指令碼來為每個project建立並配置Task。配置階段會去載入所有參與構建的專案的build.gradle檔案,會將每個build.gradle檔案例項化為一個Gradle的project物件。然後分析project之間的依賴關係,下載依賴檔案,分析project下的task之間的依賴關係。
- Execution:執行階段
這是Task真正被執行的階段,Gradle會根據依賴關係決定哪些Task需要被執行,以及執行的先後順序。
task是Gradle中的最小執行單元,我們所有的構建,編譯,打包,debug,test等都是執行了某一個task,一個project可以有多個task,task之間可以互相依賴。例如我有兩個task,taskA和taskB,指定taskA依賴taskB,然後執行taskA,這時會先去執行taskB,taskB執行完畢後在執行taskA。
說到這可能會有疑問,我翻遍了build.gradle也沒看見一個task長啥樣,有一種被欺騙的趕腳!
其實不是,你點選AndroidStudio右側的一個Gradle按鈕,會開啟一個面板,內容差不多是這樣的:
裡面的每一個條目都是一個task,那這些task是哪來的呢?
一個是根目錄下的 build.gradle
中的
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
}
一個是 app 目錄下的 build.gradle
中的
apply plugin: 'com.android.application'
這兩段程式碼決定的。也就是說,Gradle提供了一個框架,這個框架有一些執行的機制可以讓你完成編譯,但是至於怎麼編譯是由外掛決定的。還好Google已經給我們寫好了Android對應的Gradle工具,我們使用就可以了。
根目錄下的build.gradle中dependencies {classpath ‘com.android.tools.build:gradle:2.2.2’}是Android Gradle編譯外掛的版本。
app目錄下的build.gradle中的apply plugin: ‘com.android.application’是引入了Android的應用構建專案,還有com.android.library和com.android.test用來構建library和測試。
所有Android構建需要執行的task都封裝在工具裡,如果你有一些特殊需求的話,也可以自己寫一些task。那麼對於開發一個Android應用來說,最關鍵的部分就是如何來用AndroidGradle的外掛了。
認知Gradle Wrapper
Android Studio中預設會使用 Gradle Wrapper 而不是直接使用Gradle。命令也是使用gradlew而不是gradle。這是因為gradle針對特定的開發環境的構建指令碼,新的gradle可能不能相容舊版的構建環境。為了解決這個問題,使用Gradle Wrapper 來間接使用 gradle。相當於在外邊包裹了一箇中間層。對開發者來說,直接使用Gradlew 即可,不需要關心 gradle的版本變化。Gradle Wrapper 會負責下載合適的的gradle版本來構建專案。
Android 三個檔案重要的 gradle 檔案
Gradle專案有3個重要的檔案需要深入理解:專案根目錄的 build.gradle , settings.gradle 和模組目錄的 build.gradle 。
1.settings.gradle 檔案會在構建的 initialization 階段被執行,它用於告訴構建系統哪些模組需要包含到構建過程中。對於單模組專案, settings.gradle 檔案不是必需的。對於多模組專案,如果沒有該檔案,構建系統就不能知道該用到哪些模組。
2.專案根目錄的 build.gradle 檔案用來配置針對所有模組的一些屬性。它預設包含2個程式碼塊:buildscript{…}和allprojects{…}。前者用於配置構建指令碼所用到的程式碼庫和依賴關係,後者用於定義所有模組需要用到的一些公共屬性。
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
buildscript:定義了 Android 編譯工具的類路徑。repositories中, jCenter是一個著名的 Maven 倉庫。
allprojects:中定義的屬性會被應用到所有 moudle 中,但是為了保證每個專案的獨立性,我們一般不會在這裡面操作太多共有的東西。
- 3.模組級配置檔案 build.gradle 針對每個moudle 的配置,如果這裡的定義的選項和頂層 build.gradle定義的相同。它有3個重要的程式碼塊:plugin,android 和 dependencies。
定製專案屬性(project properties)
在專案根目錄的build.gradle配置檔案中,我們可以定製適用於所有模組的屬性,通過ext 程式碼塊來實現。如下所示:
ext {
compileSdkVersion = 22
buildToolsVersion = "22.0.1"
}
然後我們可以在模組目錄的build.gradle配置檔案中引用這些屬性,引用語法為rootProject.ext.{屬性名}。如下:
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
Android studio gradle Task
//構建
gradlew app:clean //移除所有的編譯輸出檔案,比如apk
gradlew app:build //構建 app module ,構建任務,相當於同時執行了check任務和assemble任務
//檢測
gradlew app:check //執行lint檢測編譯。
//打包
gradlew app:assemble //可以編譯出release包和debug包,可以使用gradlew assembleRelease或者gradlew assembleDebug來單獨編譯一種包
gradlew app:assembleRelease //app module 打 release 包
gradlew app:assembleDebug //app module 打 debug 包
//安裝,解除安裝
gradlew app:installDebug //安裝 app 的 debug 包到手機上
gradlew app:uninstallDebug //解除安裝手機上 app 的 debug 包
gradlew app:uninstallRelease //解除安裝手機上 app 的 release 包
gradlew app:uninstallAll //解除安裝手機上所有 app 的包
這些都是基本的命令,在實際專案中會根據不同的配置,會對這些task 設定不同的依賴。比如 預設的 assmeble 會依賴 assembleDebug 和assembleRelease,如果直接執行assmeble,最後會編譯debug,和release 的所有版本出來。如果我們只需要編譯debug 版本,我們可以執行assembleDebug。
除此之外還有一些常用的新增的其他命令,比如 install命令,會將編譯後的apk 安裝到連線的裝置。
lint 檢測
- 忽略編譯器的 lint 檢查
android {
lintOptions {
abortOnError false
}
}
buildTypes 定義了編譯型別
android{
buildTypes {
release {
minifyEnabled true //開啟混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false //關閉混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
productFlavors 多渠道打包
AndroidManifest.xml 裡設定動態渠道變數
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}" />
在 build.gradle 設定 productFlavors , 這裡假定我們需要打包的渠道為酷安市場、360、小米、百度、豌豆莢。
android {
productFlavors {
kuan {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "kuan"]
}
xiaomi {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
}
qh360 {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "qh360"]
}
baidu {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
}
wandoujia {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
}
}
}
或者批量修改
android {
productFlavors {
kuan {}
xiaomi {}
qh360 {}
baidu {}
wandoujia {}
}
productFlavors.all {
flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}
這樣在打包的時候就可以選擇渠道了
或者用命令打包 ,比如:
gradlew assembleWandoujiaRelease //豌豆莢 release 包
gradlew assembleWandoujiaDebug //豌豆莢 debug 包
多渠道設定包名
有時候我們需要分渠道設定 applicationId 、友盟的 appkey 、友盟渠道號。
productFlavors {
google {
applicationId "com.wifi.cool"
manifestPlaceholders = [
UMENG_APPKEY_VALUE : "456789456789",
UMENG_CHANNEL_VALUE: "google",
]
}
baidu{
applicationId 'com.wifi.hacker'
manifestPlaceholders = [
UMENG_APPKEY_VALUE : "123456789789",
UMENG_CHANNEL_VALUE : "baidu",
]
}
}
Signing 簽名
在 android 標籤下新增 signingConfigs 標籤,如下:
android {
signingConfigs {
config {
keyAlias 'yiba'
keyPassword '123456'
storeFile file('C:/work/Key.jks')
storePassword '1234567'
}
}
}
可以在 release 和 debug 包中定義簽名,如下:
android {
signingConfigs {
config {
keyAlias 'yiba'
keyPassword '123456'
storeFile file('C:/work/Key.jks')
storePassword '1234567'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}
}
}
依賴管理
1、依賴 jcenter 包
每個庫名稱包含三個元素:組名:庫名稱:版本號
compile 'com.android.support:appcompat-v7:25.0.0'
2、依賴本地 module
compile project(':YibaAnalytics')
3、依賴 jar 包
- 1、把 jar 包放在 libs 目錄下
- 2、在 build.gradle 中新增依賴
dependencies {
compile files('libs/YibaAnalytics5.jar')
}
4、依賴 aar 包
- 1、把 aar 包放到 libs 目錄下
- 2、在 build.gradle 中新增依賴
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
compile(name:'YibaAnalytics-release', ext:'aar')
}
如圖所示:
5、自定義依賴包目錄
當我們的 aar 包需要被多個 module 依賴時,我們就不能把 aar 包放在單一的 module 中,我們可以在專案的根目錄建立一個目錄,比如叫 aar 目錄,然後把我們的 aar 包放進去,如圖所示:
在專案的根目錄的 build.gradle 的 allprojects 標籤下的 repositories 新增 :
flatDir {
dirs '../aar'
}
../aar
表示根目錄下的 aar 資料夾。
如圖所示:
然後就可以新增依賴了,如下所示:
compile(name:'YibaAnalytics-release', ext:'aar')
6、依賴配置
有些時候,你可能需要和sdk協調工作。為了能順利編譯你的程式碼,你需要新增SDK到你的編譯環境。你不需要將sdk包含在你的APK中,因為它早已經存在於裝置中,所以配置來啦,我們會有5個不同的配置:
- compile
- apk
- provided
- testCompile
- androidTestCompile
compile是預設的那個,其含義是包含所有的依賴包,即在APK裡,compile的依賴會存在。
apk的意思是apk中存在,但是不會加入編譯中,這個貌似用的比較少。
provided的意思是提供編譯支援,但是不會寫入apk。
7、排除依賴相容包
有時候我們在引入依賴包的時候,會額外的引入 v7, v4 的包,對我們的專案造成額外的負擔,我們需要把這個相容包排除,可以使用 exclude 就能做到。
compile('com.google.firebase:firebase-ads:11.0.4', {
exclude group: 'com.android.support' //排除v7 , v4 包
})
native包(so包)
用c或者c++寫的library會被叫做so包,Android外掛預設情況下支援native包,你需要把.so檔案放在對應的資料夾中:
注意
jniLibs 目錄應該和 Java 目錄在同一級
defaultConfig 詳解
defaultConfig 對應的是 ProductFlavor 類。
resConfigs : 過濾語言
如果你的app中僅支援1,2種語言,但是可能引用的lib庫包含多種其他語言的strings資源,這個時候我們可以通過resConfig指定我們需要的strings資源。
android {
defaultConfig {
applicationId "com.yiba.sharewe.lite.activity"
minSdkVersion 14
targetSdkVersion 24
versionCode 46
versionName "1.74"
resConfigs 'en', 'zh-rCN' ,'es' //本次打包,只把 en(英文)、zh-rCN(中文簡體)、es(西班牙語)打進保內,其他語言忽略
}
}
resConfigs : 過濾 drawable資料夾的資源
一般情況下,我們打完包,res 下面的資源如圖所示:
現在加上資源過濾規則:
android {
defaultConfig {
applicationId "com.wifi.analytics"
minSdkVersion 9
targetSdkVersion 25
versionCode 1
versionName "1.0"
resConfigs "hdpi" //打包的時候只保留 drawable-xhdpi 資料夾裡面的資源
}
}
這次我們打包效果如下:
buildTypes 詳解
buildTypes{}對應的是 BuildType 類
繼承關係
BuildType 繼承 DefaultBuildType ; DefaultBuildType 繼承 BaseConfigImpl ;
BaseConfigImpl
--- DefaultBuildType
--- BuildType
buildTypes的屬性:
name:build type的名字
applicationIdSuffix:應用id字尾
versionNameSuffix:版本名稱字尾
debuggable:是否生成一個debug的apk
minifyEnabled:是否混淆
proguardFiles:混淆檔案
signingConfig:簽名配置
manifestPlaceholders:清單佔位符
shrinkResources:是否去除未利用的資源,預設false,表示不去除。
zipAlignEnable:是否使用zipalign工具壓縮。
multiDexEnabled:是否拆成多個Dex
multiDexKeepFile:指定文字檔案編譯進主Dex檔案中
multiDexKeepProguard:指定混淆檔案編譯進主Dex檔案中
buildType的方法:
1.buildConfigField(type,name,value):新增一個變數生成BuildConfig類。
2.consumeProguardFile(proguardFile):新增一個混淆檔案進arr包。
3.consumeProguardFile(proguardFiles):新增混淆檔案進arr包。
4.externalNativeBuild(action):配置本地的build選項。
5.initWith:複製這個build型別的所有屬性。
6.proguardFile(proguardFile):新增一個新的混淆配置檔案。
7.proguradFiles(files):新增新的混淆檔案
8.resValue(type,name,value):新增一個新的生成資源
9.setProguardFiles(proguardFileIterable):設定一個混淆配置檔案。
initWith :複製屬性
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.wifi.analytics"
minSdkVersion 9
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
myType {
initWith debug //完全複製 debug 的所有屬性‘
minifyEnabled true //自定義開啟混淆
}
}
}
applicationIdSuffix 、versionNameSuffix :新增字尾
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.wifi.analytics"
minSdkVersion 9
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
applicationIdSuffix "zhao" //applicationId 追加字尾名 zhao
versionNameSuffix "debug" //versionName 追加字尾名 debug1.0
}
}
效果圖,如下:
buildConfigField: 自定義屬性
在 build.gradle 檔案中定義 buildConfigField 屬性
android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "String", "API_ENV", "\"http://yiba.com\"" //自定義String屬性
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "String", "API_ENV", "\"http://yiba.com\"" //自定義String屬性
}
}
}
然後點選同步按鈕,然後就可以在 build 目錄看到 debug 和 release 資訊。
debug 環境下的 BuildConfig 如下:
release 環境下的 BuildConfig 如下:
當然我們也可以在程式碼中獲取自定義的值:
//獲取變數值
String API = BuildConfig.API_ENV ;
上面演示了自定義 String 變數,也可以 自定義 int 、boolean
android {
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "String", "API_ENV", "\"http://www.baidu.com\"" //自定義 String 值
buildConfigField "Boolean", "openLog", "true" //自定義 boolean 值
buildConfigField "int", "age", "10" //自定義 int 值
}
}
}
Gradle 實現差異化構建
情景1
LeakCanary 是 square 公司出品的一個檢測記憶體洩漏的開源庫。
我們一般這樣整合
dependencies {
compile 'com.squareup.leakcanary:leakcanary-android:1.5.2'
}
然後我們在 Application 類中初始化:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
但是這樣整合有一個弊端,就是 debug 和 release 包都會把 LeakCanary 的原始碼打進去,如果我們在 release 包中不把 LeakCanary 原始碼打進去,怎麼辦? 還好 LeakCanary 給我們提供了一個方法,方法如下:
dependencies {
//打 debug 包
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
//打 release 包
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
}
leakcanary-android-no-op 是一個空殼,裡面有2個空類,所以就可以避免把 LeakCanary 原始碼打進 release 包。但是這種方式有個缺陷,如果一些開源庫沒有提供 releaseCompile 庫,那我們改怎麼辦了?下面的情景2 就會講到解決方案。
情景2
Stetho 是 Faceboo k開源的Andorid除錯工具。當你的應用整合Stetho時,開發者可以訪問Chrome,在Chrome Developer Tools中檢視應用佈局,網路請求,sqlite,preference 等等。
從官網可以看到 stetho 沒有提供 releaseCompile 包 , 情景1 的方案就不能用了。新的思路整合方案如下:
dependencies {
debugCompile 'com.facebook.stetho:stetho:1.5.0'
}
在 src 目錄下建立 debug 目錄、release 目錄 ,然後分別在 debug 目錄 和 release 目錄 建立 java 目錄 , 在 java 目錄中建立包名,比如: com.app
, 如下圖所示:
debug 目錄下建立 SDKManage 類 ,如下 :
public class SDKManager {
public static void init(Context context) {
//初始化 Stetho
Stetho.initializeWithDefaults(context);
}
}
release 目錄下建立 SDKManage 類 ,如下 :
public class SDKManager {
public static void init(Context context) {
//這是一個空方法,目的是不引入 Stetho 原始碼
}
}
在住專案中的 MyApplication 類,並且完成 Stetho 的初始化,如下:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
SDKManager.init(this);
}
}
這樣我們便完成了簡單的差異化構建, 打出來的 release 包就沒有 Stetho 原始碼。
SourceSet
SourceSet 簡介
SourceSet 可以定義專案結構,也可以修改專案結構。Java外掛預設實現了兩個SourceSet,main 和 test。每個 SourceSet 都提供了一系列的屬性,通過這些屬性,可以定義該 SourceSet 所包含的原始檔。比如,java.srcDirs,resources.srcDirs 。Java 外掛中定義的其他任務,就根據 main 和 test 的這兩個 SourceSet 的定義來尋找產品程式碼和測試程式碼等。
SourceSet 定義原始碼目錄
在 Android 專案中,我們可以在 src/main/java
目錄新建 Java 檔案,如下圖所示:
現在我們在 src 目錄下,新建 test1 目錄 ,發現不能在 test1 目錄中新建 Java 檔案,如下圖所示:
為什麼在 test1 目錄不能新建 Java 檔案,因為 Gradle 中 SourceSet 預設定義的原始碼檔案路徑是src/main/java
, 其他的檔案下下面的原始碼我們自然無法訪問。解決這個問題也很簡單,我們需要在 SourceSet 中增加一個原始碼路徑即可。如下所示:
android {
sourceSets {
main {
java {
srcDir 'src/test1' //指定原始碼目錄
}
}
}
}
然後同步一下,就可以在 test1 目錄中新建 Java 檔案了。如下圖所示:
當然我們也可以同時指定多個原始碼目錄,比如同時指定 test1 , test2 , test3 為原始碼目錄。
android {
sourceSets {
main {
java {
srcDir 'src/test1' //指定 test1 為原始碼目錄
srcDir 'src/test2' //指定 test2 為原始碼目錄
srcDir 'src/test3' //指定 test3 為原始碼目錄
}
}
}
}
或者 這樣寫 :
android {
sourceSets {
main {
java.srcDirs( 'src/test1' , 'src/test2' ,'src/test3' )
}
}
}
效果如下圖所示:
SourceSet 定義資源目錄
定義 test1 目錄 Java 原始碼路徑、res 資源目錄。目錄結構如下圖所示:
android {
sourceSets {
main {
java.srcDirs('src/test1/java') //定義java 原始碼
res.srcDirs('src/test1/res') //定義資源目錄(layout , drawable,values)
}
}
}
SourceSet 實現 layout 分包
對於一個大專案來說,頁面太多,佈局檔案就很多,有時在眾多佈局檔案中找某個模組的佈局檔案,很是痛苦,為了解決這個問題,我們可以在建立多個 layout 目錄,不同模組的佈局檔案放在不同的 layout 目錄中,這樣查詢起來,就容易很多。
例子:
比如我們的專案中,有兩個模組分別為:登入、註冊。
第一步:把專案中 layout 資料夾改名字為 layouts
第二步:在 layouts 目錄下,分別建立 login 、register 目錄 。
第三步:分別在 login 、register 目錄下建立 layout 目錄。注意這一步是必須的,否則會報錯。
第四步:把 登入佈局檔案、註冊佈局檔案 分別放在 第三步建立的對應的 layout 目錄下。
效果圖如下:
SourceSet 實現如下:
android {
sourceSets {
main {
res.srcDirs 'src/main/res/layouts/login' //定義登入佈局目錄
res.srcDirs 'src/main/res/layouts/register' //定義註冊佈局目錄
}
}
}
SourceSet 定義 AndroidManifest 檔案
指定 test1 目錄下的 AndroidManifest 檔案。專案結構如下圖所示:
程式碼如下:
android {
sourceSets {
main {
manifest.srcFile 'src/test1/AndroidManifest.xml'
}
}
}
在元件化開發中, 我們需要針對 debug 與 release 模式下, 指定不同的 Manifest 檔案, 程式碼如下:
android {
def appDebug = false;
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
appDebug = false;
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
appDebug = false;
}
}
sourceSets {
main {
if (appDebug) {
manifest.srcFile 'src/test1/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
}
SourceSet 定義 assets 目錄
Android Studio 專案目錄中,assets 預設目錄如下:
如何重新定義 assets 目錄 。在專案的根目錄下建立 assets 目錄,如下圖所示:
sourceSets 定義程式碼如下:
android {
sourceSets {
main {
assets.srcDirs = ['assets']
}
}
}
SourceSet 定義其他資源
android {
sourceSets {
main {
jniLibs.srcDirs //定義 jni 目錄
aidl.srcDirs //定義 aidl 目錄
}
}
}
applicationVariants
定義 versionName 、VersionCode
在打包的時候分 debug 、release 版本 , 需要控制 versionName
android {
applicationVariants.all { variant ->
def flavor = variant.mergedFlavor
def versionName = flavor.versionName
if (variant.buildType.isDebuggable()) {
versionName += "_debug" //debug 名字
} else {
versionName += "_release" //release 名字
}
flavor.versionName = versionName
}
}
定義 APK 包的名字
apply plugin: 'com.android.application'
android {
defaultConfig {
applicationId "android.plugin"
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//定義渠道
productFlavors {
xiaomi {
//小米
}
wandoujia {
// 豌豆莢
}
}
//打包命名
applicationVariants.all {
variant ->
variant.outputs.each {
output ->
//定義一個新的apk 名字。
// 新名字 = app 名字+ 渠道號 + 構建型別 + 版本號 + 當前構建時間
def apkName = "appName_${variant.flavorName}_${buildType.name}_v${variant.versionName}_${getTime()}.apk";
output.outputFile = new File(output.outputFile.parent, apkName);
}
}
}
//獲取當前時間
def getTime() {
String today = new Date().format('YY年MM月dd日HH時mm分')
return today
}
效果圖如下:
Task
定義 task
//定義任務1
task task1<<{
println 'task1'
}
//定義任務2
task task2<<{
println 'task2'
}
mustRunAfter 定義 task 執行順序
//task2 的執行順訊在 task1 之後
task2.mustRunAfter task1
- 測試1 : gradlew task1
效果如下:
:app:task1
task1
- 測試2 : gradlew task2
效果如下:
:app:task2
task2
- 測試3 : gradlew task1 task2
效果如下:
:app:task1
task1
:app:task2
task2
- 測試4 : gradlew task2 task1
效果如下:
:app:task1
task1
:app:task2
task2
結論
如果單獨執行 task1 就只會執行 task1 的任務;單獨執行 task2 就只會執行 task2 的任務;
如果同時執行 task1、task2 , 一定會先執行 task1 , 等 task1 執行完後,就會執行 task2 內容。
擴充套件
上面 mustRunAfter 我們還有一種寫法,如下圖所示:
task2 {}.mustRunAfter task1
這個寫法的效果和 mustRunAfter 是一樣的,當然我們還可以在 花括號裡面寫一些任務,比如 :
task2 {
println '我最先執行'
}.mustRunAfter task1
下面做個測試,測試命令如下:
gradlew task2 task1
效果如下:
我最先執行
:app:task1
task1
:app:task2
task2
dependsOn 定義 task 依賴
task2 任務依賴於 task1 ,執行 task2 就會先執行 task1
task2.dependsOn task1
測試:
gradlew task2
效果如下:
:app:task1
task1
:app:task2
task2
常用 Gradlew 命令
- 1、gradlew -v : 檢視版本號
------------------------------------------------------------
Gradle 3.3
------------------------------------------------------------
Build time: 2017-01-03 15:31:04 UTC
Revision: 075893a3d0798c0c1f322899b41ceca82e4e134b
Groovy: 2.4.7
Ant: Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM: 1.8.0_112 (Oracle Corporation 25.112-b15)
OS: Windows 10 10.0 amd64
- 2、gradlew task : 檢視所有的 task
Gradle 日誌管理
Log 等級
除了常用的 debug , info , warning , error ,gradle 自己特有的 quiet 和l ifecycle 。
級別 | 用途 |
---|---|
ERROR | 錯誤資訊 |
QUIET | 重要資訊 |
WARNING | 警告資訊 |
LIFECYCLE | 警告資訊 |
INFO | 警告資訊 |
DEBUG | 除錯資訊 |
- 小例子
build.gradle
task hello << {
logger.quiet("重要資訊")
logger.info("資訊")
logger.debug("除錯資訊")
logger.lifecycle("過程資訊")
//自定義資訊等級
logger.log(LogLevel.ERROR, "錯誤資訊")
}
改變預設輸出
println 後跟資訊,gradle 會將其重定向到日誌系統中,預設為 quiet 等級。
當然你可以使用logger屬性來編寫不同等級的。
- 舉個栗子
build.gradle
task hello <<{
println( "我是一條普通的輸出")
//改變預設的標準輸出為error級別
logging.captureStandardOutput(LogLevel.ERROR)
println( "我是一條不普通的輸出")
}
效果如下:
參考資料
個人微訊號:zhaoyanjun125
, 歡迎關注