Android Gradle使用总结
轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/zhaoyanjun6/article/details/77678577
本文出自【趙彥軍的博客】
系列目錄
Android Gradle使用總結(jié)
Android Studio 插件開發(fā)詳解一:入門練手
Android Studio 插件開發(fā)詳解二:工具類
Android Studio 插件開發(fā)詳解三:翻譯插件實(shí)戰(zhàn)
Android Studio 插件開發(fā)詳解四:填坑
Android Gradle 自定義Task 詳解
Android Gradle 自定義Task詳解二:進(jìn)階
文章目錄
- 系列目錄
- Android Gradle
- Android Gradle 的 Project 和 Tasks
- Android Gradle 構(gòu)建生命周期
- 認(rèn)知Gradle Wrapper
- Android 三個文件重要的 gradle 文件
- 定制項(xiàng)目屬性(project properties)
- Android studio gradle Task
- lint 檢測
- buildTypes 定義了編譯類型
- productFlavors 多渠道打包
- 多渠道設(shè)置包名
- Signing 簽名
- 依賴管理
- 1、依賴 jcenter 包
- 2、依賴本地 module
- 3、依賴 jar 包
- 4、依賴 aar 包
- 5、自定義依賴包目錄
- 6、依賴配置
- 7、排除依賴兼容包
- native包(so包)
- defaultConfig 詳解
- resConfigs : 過濾語言
- resConfigs : 過濾 drawable文件夾的資源
- buildTypes 詳解
- initWith :復(fù)制屬性
- applicationIdSuffix 、versionNameSuffix :添加后綴
- buildConfigField: 自定義屬性
- Gradle 實(shí)現(xiàn)差異化構(gòu)建
- 情景1
- 情景2
- SourceSet
- SourceSet 簡介
- SourceSet 定義源碼目錄
- SourceSet 定義資源目錄
- SourceSet 實(shí)現(xiàn) layout 分包
- SourceSet 定義 AndroidManifest 文件
- SourceSet 定義 assets 目錄
- SourceSet 定義其他資源
- applicationVariants
- 定義 versionName 、VersionCode
- 定義 APK 包的名字
- Task
- 定義 task
- mustRunAfter 定義 task 執(zhí)行順序
- dependsOn 定義 task 依賴
- 常用 Gradlew 命令
- Gradle 日志管理
- Log 等級
- 改變默認(rèn)輸出
- 參考資料
Groovy 使用完全解析 http://blog.csdn.net/zhaoyanjun6/article/details/70313790
Android Gradle
Android項(xiàng)目使用 Gradle 作為構(gòu)建框架,Gradle 又是以Groovy為腳本語言。所以學(xué)習(xí)Gradle之前需要先熟悉Groovy腳本語言。
Groovy是基于Java語言的腳本語言,所以它的語法和Java非常相似,但是具有比java更好的靈活性。下面就列舉一些和Java的主要區(qū)別。
Android Gradle 的 Project 和 Tasks
這個Gradle中最重要的兩個概念。每次構(gòu)建(build)至少由一個project構(gòu)成,一個project 由一到多個task構(gòu)成。項(xiàng)目結(jié)構(gòu)中的每個build.gradle文件代表一個project,在這編譯腳本文件中可以定義一系列的task;task 本質(zhì)上又是由一組被順序執(zhí)行的Action`對象構(gòu)成,Action其實(shí)是一段代碼塊,類似于Java中的方法。
Android Gradle 構(gòu)建生命周期
每次構(gòu)建的執(zhí)行本質(zhì)上執(zhí)行一系列的Task。某些Task可能依賴其他Task。哪些沒有依賴的Task總會被最先執(zhí)行,而且每個Task只會被執(zhí)行一遍。每次構(gòu)建的依賴關(guān)系是在構(gòu)建的配置階段確定的。每次構(gòu)建分為3個階段:
- Initialization: 初始化階段
這是創(chuàng)建Project階段,構(gòu)建工具根據(jù)每個build.gradle文件創(chuàng)建出一個Project實(shí)例。初始化階段會執(zhí)行項(xiàng)目根目錄下的settings.gradle文件,來分析哪些項(xiàng)目參與構(gòu)建。
所以這個文件里面的內(nèi)容經(jīng)常是:
include ':app' include ':libraries:someProject'這是告訴Gradle這些項(xiàng)目需要編譯,所以我們引入一些開源的項(xiàng)目的時候,需要在這里填上對應(yīng)的項(xiàng)目名稱,來告訴Gradle這些項(xiàng)目需要參與構(gòu)建。
- Configuration:配置階段
這個階段,通過執(zhí)行構(gòu)建腳本來為每個project創(chuàng)建并配置Task。配置階段會去加載所有參與構(gòu)建的項(xiàng)目的build.gradle文件,會將每個build.gradle文件實(shí)例化為一個Gradle的project對象。然后分析project之間的依賴關(guān)系,下載依賴文件,分析project下的task之間的依賴關(guān)系。
- Execution:執(zhí)行階段
這是Task真正被執(zhí)行的階段,Gradle會根據(jù)依賴關(guān)系決定哪些Task需要被執(zhí)行,以及執(zhí)行的先后順序。
task是Gradle中的最小執(zhí)行單元,我們所有的構(gòu)建,編譯,打包,debug,test等都是執(zhí)行了某一個task,一個project可以有多個task,task之間可以互相依賴。例如我有兩個task,taskA和taskB,指定taskA依賴taskB,然后執(zhí)行taskA,這時會先去執(zhí)行taskB,taskB執(zhí)行完畢后在執(zhí)行taskA。
說到這可能會有疑問,我翻遍了build.gradle也沒看見一個task長啥樣,有一種被欺騙的趕腳!
其實(shí)不是,你點(diǎn)擊AndroidStudio右側(cè)的一個Gradle按鈕,會打開一個面板,內(nèi)容差不多是這樣的:
里面的每一個條目都是一個task,那這些task是哪來的呢?
一個是根目錄下的 build.gradle 中的
dependencies {classpath 'com.android.tools.build:gradle:2.2.2'}一個是 app 目錄下的 build.gradle 中的
apply plugin: 'com.android.application'這兩段代碼決定的。也就是說,Gradle提供了一個框架,這個框架有一些運(yùn)行的機(jī)制可以讓你完成編譯,但是至于怎么編譯是由插件決定的。還好Google已經(jīng)給我們寫好了Android對應(yīng)的Gradle工具,我們使用就可以了。
根目錄下的build.gradle中dependencies {classpath ‘com.android.tools.build:gradle:2.2.2’}是Android Gradle編譯插件的版本。
app目錄下的build.gradle中的apply plugin: 'com.android.application’是引入了Android的應(yīng)用構(gòu)建項(xiàng)目,還有com.android.library和com.android.test用來構(gòu)建library和測試。
所有Android構(gòu)建需要執(zhí)行的task都封裝在工具里,如果你有一些特殊需求的話,也可以自己寫一些task。那么對于開發(fā)一個Android應(yīng)用來說,最關(guān)鍵的部分就是如何來用AndroidGradle的插件了。
認(rèn)知Gradle Wrapper
Android Studio中默認(rèn)會使用 Gradle Wrapper 而不是直接使用Gradle。命令也是使用gradlew而不是gradle。這是因?yàn)間radle針對特定的開發(fā)環(huán)境的構(gòu)建腳本,新的gradle可能不能兼容舊版的構(gòu)建環(huán)境。為了解決這個問題,使用Gradle Wrapper 來間接使用 gradle。相當(dāng)于在外邊包裹了一個中間層。對開發(fā)者來說,直接使用Gradlew 即可,不需要關(guān)心 gradle的版本變化。Gradle Wrapper 會負(fù)責(zé)下載合適的的gradle版本來構(gòu)建項(xiàng)目。
Android 三個文件重要的 gradle 文件
Gradle項(xiàng)目有3個重要的文件需要深入理解:項(xiàng)目根目錄的 build.gradle , settings.gradle 和模塊目錄的 build.gradle 。
-
1.settings.gradle 文件會在構(gòu)建的 initialization 階段被執(zhí)行,它用于告訴構(gòu)建系統(tǒng)哪些模塊需要包含到構(gòu)建過程中。對于單模塊項(xiàng)目, settings.gradle 文件不是必需的。對于多模塊項(xiàng)目,如果沒有該文件,構(gòu)建系統(tǒng)就不能知道該用到哪些模塊。
-
2.項(xiàng)目根目錄的 build.gradle 文件用來配置針對所有模塊的一些屬性。它默認(rèn)包含2個代碼塊:buildscript{…}和allprojects{…}。前者用于配置構(gòu)建腳本所用到的代碼庫和依賴關(guān)系,后者用于定義所有模塊需要用到的一些公共屬性。
buildscript:定義了 Android 編譯工具的類路徑。repositories中, jCenter是一個著名的 Maven 倉庫。
allprojects:中定義的屬性會被應(yīng)用到所有 moudle 中,但是為了保證每個項(xiàng)目的獨(dú)立性,我們一般不會在這里面操作太多共有的東西。
- 3.模塊級配置文件 build.gradle 針對每個moudle 的配置,如果這里的定義的選項(xiàng)和頂層 build.gradle定義的相同。它有3個重要的代碼塊:plugin,android 和 dependencies。
定制項(xiàng)目屬性(project properties)
在項(xiàng)目根目錄的build.gradle配置文件中,我們可以定制適用于所有模塊的屬性,通過ext 代碼塊來實(shí)現(xiàn)。如下所示:
ext {compileSdkVersion = 22buildToolsVersion = "22.0.1" }然后我們可以在模塊目錄的build.gradle配置文件中引用這些屬性,引用語法為rootProject.ext.{屬性名}。如下:
android {compileSdkVersion rootProject.ext.compileSdkVersionbuildToolsVersion rootProject.ext.buildToolsVersion }Android studio gradle Task
//構(gòu)建 gradlew app:clean //移除所有的編譯輸出文件,比如apkgradlew app:build //構(gòu)建 app module ,構(gòu)建任務(wù),相當(dāng)于同時執(zhí)行了check任務(wù)和assemble任務(wù)//檢測 gradlew app:check //執(zhí)行l(wèi)int檢測編譯。//打包 gradlew app:assemble //可以編譯出release包和debug包,可以使用gradlew assembleRelease或者gradlew assembleDebug來單獨(dú)編譯一種包gradlew app:assembleRelease //app module 打 release 包gradlew app:assembleDebug //app module 打 debug 包//安裝,卸載gradlew app:installDebug //安裝 app 的 debug 包到手機(jī)上gradlew app:uninstallDebug //卸載手機(jī)上 app 的 debug 包gradlew app:uninstallRelease //卸載手機(jī)上 app 的 release 包gradlew app:uninstallAll //卸載手機(jī)上所有 app 的包這些都是基本的命令,在實(shí)際項(xiàng)目中會根據(jù)不同的配置,會對這些task 設(shè)置不同的依賴。比如 默認(rèn)的 assmeble 會依賴 assembleDebug 和assembleRelease,如果直接執(zhí)行assmeble,最后會編譯debug,和release 的所有版本出來。如果我們只需要編譯debug 版本,我們可以運(yùn)行assembleDebug。
除此之外還有一些常用的新增的其他命令,比如 install命令,會將編譯后的apk 安裝到連接的設(shè)備。
lint 檢測
- 忽略編譯器的 lint 檢查
buildTypes 定義了編譯類型
android{buildTypes {release {minifyEnabled true //打開混淆proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {minifyEnabled false //關(guān)閉混淆proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}}productFlavors 多渠道打包
AndroidManifest.xml 里設(shè)置動態(tài)渠道變量
<meta-dataandroid:name="UMENG_CHANNEL"android:value="${UMENG_CHANNEL_VALUE}" />在 build.gradle 設(shè)置 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 包多渠道設(shè)置包名
有時候我們需要分渠道設(shè)置 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 標(biāo)簽下添加 signingConfigs 標(biāo)簽,如下:
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 falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'signingConfig signingConfigs.config}debug {minifyEnabled falseproguardFiles 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 中添加依賴
4、依賴 aar 包
- 1、把 aar 包放到 libs 目錄下
- 2、在 build.gradle 中添加依賴
如圖所示:
5、自定義依賴包目錄
當(dāng)我們的 aar 包需要被多個 module 依賴時,我們就不能把 aar 包放在單一的 module 中,我們可以在項(xiàng)目的根目錄創(chuàng)建一個目錄,比如叫 aar 目錄,然后把我們的 aar 包放進(jìn)去,如圖所示:
在項(xiàng)目的根目錄的 build.gradle 的 allprojects 標(biāo)簽下的 repositories 添加 :
flatDir {dirs '../aar' }../aar 表示根目錄下的 aar 文件夾。
如圖所示:
然后就可以添加依賴了,如下所示:
compile(name:'YibaAnalytics-release', ext:'aar')6、依賴配置
有些時候,你可能需要和sdk協(xié)調(diào)工作。為了能順利編譯你的代碼,你需要添加SDK到你的編譯環(huán)境。你不需要將sdk包含在你的APK中,因?yàn)樗缫呀?jīng)存在于設(shè)備中,所以配置來啦,我們會有5個不同的配置:
- compile
- apk
- provided
- testCompile
- androidTestCompile
compile是默認(rèn)的那個,其含義是包含所有的依賴包,即在APK里,compile的依賴會存在。
apk的意思是apk中存在,但是不會加入編譯中,這個貌似用的比較少。
provided的意思是提供編譯支持,但是不會寫入apk。
7、排除依賴兼容包
有時候我們在引入依賴包的時候,會額外的引入 v7, v4 的包,對我們的項(xiàng)目造成額外的負(fù)擔(dān),我們需要把這個兼容包排除,可以使用 exclude 就能做到。
compile('com.google.firebase:firebase-ads:11.0.4', {exclude group: 'com.android.support' //排除v7 , v4 包 })native包(so包)
用c或者c++寫的library會被叫做so包,Android插件默認(rèn)情況下支持native包,你需要把.so文件放在對應(yīng)的文件夾中:
注意
jniLibs 目錄應(yīng)該和 Java 目錄在同一級
defaultConfig 詳解
defaultConfig 對應(yīng)的是 ProductFlavor 類。
resConfigs : 過濾語言
如果你的app中僅支持1,2種語言,但是可能引用的lib庫包含多種其他語言的strings資源,這個時候我們可以通過resConfig指定我們需要的strings資源。
android {defaultConfig {applicationId "com.yiba.sharewe.lite.activity"minSdkVersion 14targetSdkVersion 24versionCode 46versionName "1.74"resConfigs 'en', 'zh-rCN' ,'es' //本次打包,只把 en(英文)、zh-rCN(中文簡體)、es(西班牙語)打進(jìn)保內(nèi),其他語言忽略} }resConfigs : 過濾 drawable文件夾的資源
一般情況下,我們打完包,res 下面的資源如圖所示:
現(xiàn)在加上資源過濾規(guī)則:
android {defaultConfig {applicationId "com.wifi.analytics"minSdkVersion 9targetSdkVersion 25versionCode 1versionName "1.0"resConfigs "hdpi" //打包的時候只保留 drawable-xhdpi 文件夾里面的資源}}這次我們打包效果如下:
buildTypes 詳解
官方文檔
buildTypes{}對應(yīng)的是 BuildType 類
繼承關(guān)系
BuildType 繼承 DefaultBuildType ; DefaultBuildType 繼承 BaseConfigImpl ;
BaseConfigImpl--- DefaultBuildType --- BuildTypebuildTypes的屬性:
name:build type的名字applicationIdSuffix:應(yīng)用id后綴versionNameSuffix:版本名稱后綴debuggable:是否生成一個debug的apkminifyEnabled:是否混淆proguardFiles:混淆文件signingConfig:簽名配置manifestPlaceholders:清單占位符shrinkResources:是否去除未利用的資源,默認(rèn)false,表示不去除。zipAlignEnable:是否使用zipalign工具壓縮。multiDexEnabled:是否拆成多個DexmultiDexKeepFile:指定文本文件編譯進(jìn)主Dex文件中multiDexKeepProguard:指定混淆文件編譯進(jìn)主Dex文件中buildType的方法:
1.buildConfigField(type,name,value):添加一個變量生成BuildConfig類。2.consumeProguardFile(proguardFile):添加一個混淆文件進(jìn)arr包。3.consumeProguardFile(proguardFiles):添加混淆文件進(jìn)arr包。4.externalNativeBuild(action):配置本地的build選項(xiàng)。5.initWith:復(fù)制這個build類型的所有屬性。6.proguardFile(proguardFile):添加一個新的混淆配置文件。7.proguradFiles(files):添加新的混淆文件8.resValue(type,name,value):添加一個新的生成資源9.setProguardFiles(proguardFileIterable):設(shè)置一個混淆配置文件。initWith :復(fù)制屬性
android {compileSdkVersion 25buildToolsVersion "25.0.2"defaultConfig {applicationId "com.wifi.analytics"minSdkVersion 9targetSdkVersion 25versionCode 1versionName "1.0"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}myType {initWith debug //完全復(fù)制 debug 的所有屬性‘minifyEnabled true //自定義打開混淆}} }applicationIdSuffix 、versionNameSuffix :添加后綴
android {compileSdkVersion 25buildToolsVersion "25.0.2"defaultConfig {applicationId "com.wifi.analytics"minSdkVersion 9targetSdkVersion 25versionCode 1versionName "1.0"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'applicationIdSuffix "zhao" //applicationId 追加后綴名 zhaoversionNameSuffix "debug" //versionName 追加后綴名 debug1.0}}效果圖,如下:
buildConfigField: 自定義屬性
在 build.gradle 文件中定義 buildConfigField 屬性
android {buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'buildConfigField "String", "API_ENV", "\"http://yiba.com\"" //自定義String屬性}debug {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'buildConfigField "String", "API_ENV", "\"http://yiba.com\"" //自定義String屬性}} }然后點(diǎn)擊同步按鈕,然后就可以在 build 目錄看到 debug 和 release 信息。
debug 環(huán)境下的 BuildConfig 如下:
release 環(huán)境下的 BuildConfig 如下:
當(dāng)然我們也可以在代碼中獲取自定義的值:
//獲取變量值 String API = BuildConfig.API_ENV ;上面演示了自定義 String 變量,也可以 自定義 int 、boolean
android {buildTypes {debug {minifyEnabled falseproguardFiles 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 實(shí)現(xiàn)差異化構(gòu)建
情景1
LeakCanary 是 square 公司出品的一個檢測內(nèi)存泄漏的開源庫。
GitHub : https://github.com/square/leakcanary
我們一般這樣集成
dependencies {compile 'com.squareup.leakcanary:leakcanary-android:1.5.2' }然后我們在 Application 類中初始化:
public class MyApplication extends Application {@Overridepublic void onCreate() {super.onCreate();LeakCanary.install(this);} }但是這樣集成有一個弊端,就是 debug 和 release 包都會把 LeakCanary 的源碼打進(jìn)去,如果我們在 release 包中不把 LeakCanary 源碼打進(jìn)去,怎么辦? 還好 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 源碼打進(jìn) release 包。但是這種方式有個缺陷,如果一些開源庫沒有提供 releaseCompile 庫,那我們改怎么辦了?下面的情景2 就會講到解決方案。
情景2
Stetho 是 Faceboo k開源的Andorid調(diào)試工具。當(dāng)你的應(yīng)用集成Stetho時,開發(fā)者可以訪問Chrome,在Chrome Developer Tools中查看應(yīng)用布局,網(wǎng)絡(luò)請求,sqlite,preference 等等。
官網(wǎng):http://facebook.github.io/stetho/
從官網(wǎng)可以看到 stetho 沒有提供 releaseCompile 包 , 情景1 的方案就不能用了。新的思路集成方案如下:
dependencies {debugCompile 'com.facebook.stetho:stetho:1.5.0' }在 src 目錄下創(chuàng)建 debug 目錄、release 目錄 ,然后分別在 debug 目錄 和 release 目錄 創(chuàng)建 java 目錄 , 在 java 目錄中創(chuàng)建包名,比如: com.app , 如下圖所示:
debug 目錄下創(chuàng)建 SDKManage 類 ,如下 :
public class SDKManager {public static void init(Context context) {//初始化 StethoStetho.initializeWithDefaults(context);} }release 目錄下創(chuàng)建 SDKManage 類 ,如下 :
public class SDKManager {public static void init(Context context) { //這是一個空方法,目的是不引入 Stetho 源碼}}在住項(xiàng)目中的 MyApplication 類,并且完成 Stetho 的初始化,如下:
public class MyApplication extends Application {@Overridepublic void onCreate() {super.onCreate();SDKManager.init(this);} }這樣我們便完成了簡單的差異化構(gòu)建, 打出來的 release 包就沒有 Stetho 源碼。
SourceSet
SourceSet 簡介
SourceSet 可以定義項(xiàng)目結(jié)構(gòu),也可以修改項(xiàng)目結(jié)構(gòu)。Java插件默認(rèn)實(shí)現(xiàn)了兩個SourceSet,main 和 test。每個 SourceSet 都提供了一系列的屬性,通過這些屬性,可以定義該 SourceSet 所包含的源文件。比如,java.srcDirs,resources.srcDirs 。Java 插件中定義的其他任務(wù),就根據(jù) main 和 test 的這兩個 SourceSet 的定義來尋找產(chǎn)品代碼和測試代碼等。
SourceSet 定義源碼目錄
在 Android 項(xiàng)目中,我們可以在 src/main/java 目錄新建 Java 文件,如下圖所示:
現(xiàn)在我們在 src 目錄下,新建 test1 目錄 ,發(fā)現(xiàn)不能在 test1 目錄中新建 Java 文件,如下圖所示:
為什么在 test1 目錄不能新建 Java 文件,因?yàn)?Gradle 中 SourceSet 默認(rèn)定義的源碼文件路徑是src/main/java , 其他的文件下下面的源碼我們自然無法訪問。解決這個問題也很簡單,我們需要在 SourceSet 中增加一個源碼路徑即可。如下所示:
android {sourceSets {main {java {srcDir 'src/test1' //指定源碼目錄}}} }然后同步一下,就可以在 test1 目錄中新建 Java 文件了。如下圖所示:
當(dāng)然我們也可以同時指定多個源碼目錄,比如同時指定 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 資源目錄。目錄結(jié)構(gòu)如下圖所示:
android {sourceSets {main {java.srcDirs('src/test1/java') //定義java 源代碼res.srcDirs('src/test1/res') //定義資源目錄(layout , drawable,values)}} }SourceSet 實(shí)現(xiàn) layout 分包
對于一個大項(xiàng)目來說,頁面太多,布局文件就很多,有時在眾多布局文件中找某個模塊的布局文件,很是痛苦,為了解決這個問題,我們可以在創(chuàng)建多個 layout 目錄,不同模塊的布局文件放在不同的 layout 目錄中,這樣查找起來,就容易很多。
例子:
比如我們的項(xiàng)目中,有兩個模塊分別為:登錄、注冊。
-
第一步:把項(xiàng)目中 layout 文件夾改名字為 layouts
-
第二步:在 layouts 目錄下,分別創(chuàng)建 login 、register 目錄 。
-
第三步:分別在 login 、register 目錄下創(chuàng)建 layout 目錄。注意這一步是必須的,否則會報錯。
-
第四步:把 登錄布局文件、注冊布局文件 分別放在 第三步創(chuàng)建的對應(yīng)的 layout 目錄下。
效果圖如下:
SourceSet 實(shí)現(xiàn)如下:
android {sourceSets {main {res.srcDirs 'src/main/res/layouts/login' //定義登錄布局目錄res.srcDirs 'src/main/res/layouts/register' //定義注冊布局目錄}} }SourceSet 定義 AndroidManifest 文件
指定 test1 目錄下的 AndroidManifest 文件。項(xiàng)目結(jié)構(gòu)如下圖所示:
代碼如下:
android {sourceSets {main {manifest.srcFile 'src/test1/AndroidManifest.xml'}} }在組件化開發(fā)中, 我們需要針對 debug 與 release 模式下, 指定不同的 Manifest 文件, 代碼如下:
android {def appDebug = false;buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'appDebug = false;}debug {minifyEnabled falseproguardFiles 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 項(xiàng)目目錄中,assets 默認(rèn)目錄如下:
如何重新定義 assets 目錄 。在項(xiàng)目的根目錄下創(chuàng)建 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.mergedFlavordef versionName = flavor.versionNameif (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 14targetSdkVersion 25versionCode 1versionName "1.0"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}//定義渠道productFlavors {xiaomi {//小米}wandoujia {// 豌豆莢}}//打包命名applicationVariants.all {variant ->variant.outputs.each {output ->//定義一個新的apk 名字。// 新名字 = app 名字+ 渠道號 + 構(gòu)建類型 + 版本號 + 當(dāng)前構(gòu)建時間def apkName = "appName_${variant.flavorName}_${buildType.name}_v${variant.versionName}_${getTime()}.apk";output.outputFile = new File(output.outputFile.parent, apkName);}}}//獲取當(dāng)前時間 def getTime() {String today = new Date().format('YY年MM月dd日HH時mm分')return today }效果圖如下:
Task
定義 task
//定義任務(wù)1 task task1<<{println 'task1' }//定義任務(wù)2 task task2<<{println 'task2' }mustRunAfter 定義 task 執(zhí)行順序
//task2 的執(zhí)行順訊在 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結(jié)論
如果單獨(dú)執(zhí)行 task1 就只會執(zhí)行 task1 的任務(wù);單獨(dú)執(zhí)行 task2 就只會執(zhí)行 task2 的任務(wù);
如果同時執(zhí)行 task1、task2 , 一定會先執(zhí)行 task1 , 等 task1 執(zhí)行完后,就會執(zhí)行 task2 內(nèi)容。
擴(kuò)展
上面 mustRunAfter 我們還有一種寫法,如下圖所示:
task2 {}.mustRunAfter task1這個寫法的效果和 mustRunAfter 是一樣的,當(dāng)然我們還可以在 花括號里面寫一些任務(wù),比如 :
task2 {println '我最先執(zhí)行' }.mustRunAfter task1下面做個測試,測試命令如下:
gradlew task2 task1效果如下:
我最先執(zhí)行:app:task1 task1 :app:task2 task2dependsOn 定義 task 依賴
task2 任務(wù)依賴于 task1 ,執(zhí)行 task2 就會先執(zhí)行 task1
task2.dependsOn task1測試:
gradlew task2效果如下:
:app:task1 task1 :app:task2 task2常用 Gradlew 命令
- 1、gradlew -v : 查看版本號
- 2、gradlew task : 查看所有的 task
Gradle 日志管理
Log 等級
除了常用的 debug , info , warning , error ,gradle 自己特有的 quiet 和l ifecycle 。
| ERROR | 錯誤信息 |
| QUIET | 重要信息 |
| WARNING | 警告信息 |
| LIFECYCLE | 警告信息 |
| INFO | 警告信息 |
| DEBUG | 調(diào)試信息 |
- 小例子
build.gradle
task hello << {logger.quiet("重要信息")logger.info("信息")logger.debug("調(diào)試信息")logger.lifecycle("過程信息")//自定義信息等級logger.log(LogLevel.ERROR, "錯誤信息")}改變默認(rèn)輸出
println 后跟信息,gradle 會將其重定向到日志系統(tǒng)中,默認(rèn)為 quiet 等級。
當(dāng)然你可以使用logger屬性來編寫不同等級的。
- 舉個栗子
build.gradle
task hello <<{println( "我是一條普通的輸出")//改變默認(rèn)的標(biāo)準(zhǔn)輸出為error級別logging.captureStandardOutput(LogLevel.ERROR)println( "我是一條不普通的輸出") }效果如下:
參考資料
Android 利用Gradle實(shí)現(xiàn)差異化構(gòu)建
楊海 Android目錄結(jié)構(gòu)
個人微信號:zhaoyanjun125 , 歡迎關(guān)注
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-YbAN8mrk-1604564656923)(http://o7rvuansr.bkt.clouddn.com/weixin200.jpg)]
總結(jié)
以上是生活随笔為你收集整理的Android Gradle使用总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jenkins实现Android自动化打
- 下一篇: Android Studio 插件开发详