說(shuō)明
本文主要介紹和Gradle關(guān)系密切、相對(duì)不容易理解的配置,偏重概念介紹。部分內(nèi)容是Android特有的(例如ProductFlavor),其他內(nèi)容則是所有Gradle工程都相同或類似的知識(shí)。
對(duì)于一些常規(guī)且相對(duì)簡(jiǎn)單的配置項(xiàng),例如簽名配置SigningConfig,不做具體介紹。而部分比較復(fù)雜且不太常用的內(nèi)容,例如Manifest的具體合并規(guī)則,只做簡(jiǎn)單說(shuō)明,并給出深入學(xué)習(xí)的相關(guān)鏈接,讀者可自行閱讀。
文章主要基于Gradle V3.3 + Android Gradle Plugin V2.3 + Android Studio 2.3,在后續(xù)版本升級(jí)后部分內(nèi)容可能會(huì)改變。
文中的內(nèi)容,有些是根據(jù)源碼分析得到,有些是參考了官方文檔,還有些參考了網(wǎng)上的文章。如有不正確的地方,歡迎指正。
關(guān)于Gradle DSL的語(yǔ)法原理和開(kāi)發(fā)相關(guān)知識(shí),可參考我的另一篇文章
Gradle開(kāi)發(fā)快速入門——DSL語(yǔ)法原理與常用API介紹
http://www.paincker.com/gradle-develop-basics
基本問(wèn)題
開(kāi)始看本文前,可以思考下面這些關(guān)于Gradle的基本問(wèn)題。文中會(huì)對(duì)這些問(wèn)題進(jìn)行解釋。
settings.gradle有什么作用?
repositories {}語(yǔ)句塊的作用?buildscript和allprojects的區(qū)別?ProductFlavor和BuildType的區(qū)別?
依賴沖突的原因和常見(jiàn)解決思路?
classpath 'com.android.tools.build:gradle:2.2.3',有什么作用?gradle/wrapper/gradle-wrapper.properties中的這句有什么作用?
distributionUrl=https://services.gradle.org/distributions/gradle-2.14.1-all.zip命令行中,gradle assemble、gradle assembleDebug、gradle build 的關(guān)系?
Android Studio環(huán)境下,Gradle Sync操作做了什么工作?
Gradle
Gradle是一個(gè)基于Groovy語(yǔ)言的強(qiáng)大的構(gòu)建系統(tǒng),Groovy則是在Java基礎(chǔ)上擴(kuò)展的、運(yùn)行在JVM上的一種腳本語(yǔ)言。
通過(guò)豐富的插件擴(kuò)展,Gradle可以支持Java、JavaWeb、Groovy、Android等工程的編譯,同時(shí)可以很方便的從Maven、Ant等遷移過(guò)來(lái)。
C系列語(yǔ)言也有相應(yīng)的Gradle插件,但Gradle支持最好的還是Java系列語(yǔ)言。
Gradle也是一個(gè)命令行可執(zhí)行程序,可從官網(wǎng)下載Gradle,可執(zhí)行文件位于bin/gradle。
執(zhí)行Gradle任務(wù)的過(guò)程,主要就是在運(yùn)行Java/Groovy代碼。編譯期間如果有代碼拋出了異常,就會(huì)中斷編譯過(guò)程。
在Android Studio中開(kāi)發(fā)時(shí),編譯就是基于Gradle實(shí)現(xiàn)的。Android Studio中內(nèi)置了Gradle。
Gradle官網(wǎng)
https://gradle.org/
Gradle Wrapper
用IDEA/Android Studio創(chuàng)建基于Gradle的工程時(shí),默認(rèn)會(huì)在工程根目錄創(chuàng)建GradleWrapper,包括gradlew可執(zhí)行腳本和gradle/wrapper文件夾,其中指定了和工程配套的gradle版本。
在工程根目錄下直接執(zhí)行./gradlew,會(huì)自動(dòng)將參數(shù)傳給wrapper指定版本的gradle,執(zhí)行對(duì)應(yīng)的命令;如果本機(jī)還沒(méi)有該版本的gradle,則會(huì)先自動(dòng)下載。
工程配置和Gradle版本通常需要對(duì)應(yīng),不正確的Gradle版本可能無(wú)法正常編譯工程,因此推薦使用GradleWrapper執(zhí)行Gradle命令。
gradle/wrapper/gradle-wrapper.properties文件,指定了gradle版本、下載地址、下載的文件存放位置(Mac系統(tǒng)中默認(rèn)在~/.gradle/wrapper/dists目錄)。此文件內(nèi)容示例:
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
在Android Studio/IDEA中,可通過(guò)Preferences - Build, Execution, Deployment - Gradle,設(shè)置Project-level settings中Use default gradle wrapper,指定Android Studio使用工程配置的Gradle Wrapper。
DSL、DSL Reference
Gradle使用Groovy語(yǔ)言封裝了一整套API,通常把這套API稱為DSL(Domain-Specific Languages,領(lǐng)域特定語(yǔ)言)。
通常在我們配置Gradle編譯參數(shù)時(shí),所寫的gradle腳本從形式上來(lái)看,像是一門有著特殊語(yǔ)法格式的語(yǔ)言。
Gradle封裝的DSL,按照固定格式用很簡(jiǎn)單的語(yǔ)法就能實(shí)現(xiàn)很復(fù)雜的配置,大大簡(jiǎn)化了配置工作。另一方面,也正是由于封裝的非常完善,想深入學(xué)習(xí)Gradle,會(huì)感覺(jué)無(wú)從下手。
可以通過(guò)DSL Reference文檔查看Gradle DSL支持的語(yǔ)法配置項(xiàng)。例如:
Gradle DSL Reference(Gradle原生支持的DSL配置)
https://docs.gradle.org/current/dsl/
Android Plugin DSL Reference(Android的DSL配置)
http://google.github.io/android-gradle-dsl/current/
關(guān)于Gradle DSL的語(yǔ)法原理和開(kāi)發(fā)相關(guān)知識(shí),可參考我的另一篇文章
Gradle開(kāi)發(fā)快速入門——DSL語(yǔ)法原理與常用API介紹
http://www.paincker.com/gradle-develop-basics
Project、RootProject、SubProject (Module)
Project是Gradle中的基本概念之一,即一個(gè)工程。一個(gè)工程可以包含多個(gè)SubProject,也稱為Module,最頂層的工程也稱為RootProject。
一個(gè)標(biāo)準(zhǔn)的Android工程,文件結(jié)構(gòu)如下。
每個(gè)
build.gradle對(duì)應(yīng)一個(gè)Project,最外層的是RootProject,里面的app是SubProject。settings.gradle不是必須的,一般在包含子工程時(shí)就需要用這個(gè)文件指定,即我們通常所見(jiàn)的include ':app'腳本。這里的
':app'就是子工程的名字,通常和文件夾名稱對(duì)應(yīng)。
settings.gradle
build.gradle
app
build.gradle
StartParameter
Gradle執(zhí)行時(shí)有一些稱為StartParameter的參數(shù),StartParameter可在命令行設(shè)置,可通過(guò)gradle --help查看。例如:
-
--quiet,執(zhí)行過(guò)程中,只顯示Error級(jí)別的Log。 -
--stacktrace,執(zhí)行過(guò)程中,輸出所有Exception的stacktrace。 -
--full-stacktrace,執(zhí)行過(guò)程中,輸出所有Exception的完整stacktrace。 -
--no-daemon,不使用Deamon。Deamon是用于加速Gradle執(zhí)行的后臺(tái)進(jìn)程,有些情況下使用Deamon會(huì)有問(wèn)題(可參考 https://docs.gradle.org/current/userguide/gradle_daemon.html) -
--offline,離線模式,不使用網(wǎng)絡(luò)資源。
在命令行可通過(guò)-P參數(shù)傳入projectProperties,并在Gradle腳本中獲取
# 命令行傳入projectProperties
./gradlew clean -Pkey=value
// gradle腳本中獲取projectProperties
print gradle.startParameter.projectProperties.get('key')
還可以通過(guò)-D參數(shù)傳入systemPropertiesArgs,并在Gradle腳本中獲取
# 命令行傳入systemPropertiesArgs
./gradlew clean -Dkey=value
// gradle腳本中獲取systemPropertiesArgs
print gradle.startParameter.systemPropertiesArgs.get('key')
gradle.properties
Properties文件格式可由java.util.Properties解析,包含若干鍵值對(duì),類似HashMap<String,String>。
Gradle運(yùn)行時(shí)會(huì)自動(dòng)讀取gradle.properties文件并引用其中的屬性。有多個(gè)位置可以放gradle.properties文件,按優(yōu)先級(jí)從低到高如下:
- Project所在目錄(即build.gradle所在目錄),包括RootProject和SubProject
- GradleHome目錄(Mac中默認(rèn)為
~/gradle) - 通過(guò)gradle命令行
-D參數(shù)指定的Property
在gradle.properties文件中,一些保留Key可用于配置Gradle運(yùn)行環(huán)境,例如org.gradle.daemon用于設(shè)置GradleDeamon,org.gradle.logging.level用于設(shè)置Gradle的Log級(jí)別等。
詳情可參考
https://docs.gradle.org/current/userguide/build_environment.html
除了保留Key以外,其他Key都可以作為變量用于配置工程。例如在Project目錄的gradle.properties中統(tǒng)一定義Support包的版本號(hào),然后在build.gradle中使用定義的變量如下。
SUPPORT_LIBRARY_VERSION=23.4.0
dependencies {
compile "com.android.support:support-v4:${SUPPORT_LIBRARY_VERSION}"
compile "com.android.support:appcompat-v7:${SUPPORT_LIBRARY_VERSION}"
compile "com.android.support:design:${SUPPORT_LIBRARY_VERSION}"
compile "com.android.support:recyclerview-v7:${SUPPORT_LIBRARY_VERSION}"
}
Gradle Task
Gradle以Task(任務(wù))的形式組織每一步操作,每個(gè)Task執(zhí)行一個(gè)原子操作(例如把Java編譯成class文件、把class打成jar/dex文件、APK簽名等)。
每個(gè)Project包含若干Task,Task之間存在依賴關(guān)系,執(zhí)行一個(gè)Task前,會(huì)先執(zhí)行它所依賴的Task。
每個(gè)Task有自己的名字(例如'assemble'),結(jié)合其所屬Project的名字(例如':app'),可以組成完整名(例如':app:assemble')。
Gradle內(nèi)建了一個(gè)名為tasks的Task,可以列舉Project中的所有Task。
執(zhí)行Task,查看Project中的所有Task
執(zhí)行Task時(shí),直接把Task名稱傳給gradle即可。
如果下載了Gradle并配置了環(huán)境變量,則可在工程根目錄執(zhí)行:
gradle tasks
更推薦的做法,是在工程根目錄下調(diào)用GradleWrapper執(zhí)行:
./gradlew tasks
執(zhí)行結(jié)果如下(省略了部分輸出):
$ ./gradlew tasks
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.
signingReport - Displays the signing info for each variant.
sourceSets - Prints out all the source sets defined in this project.
Build tasks
-----------
assemble - Assembles all variants of all applications and secondary packages.
assembleAndroidTest - Assembles all the Test applications.
assembleDebug - Assembles all Debug builds.
assembleRelease - Assembles all Release builds.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
cleanBuildCache - Deletes the build cache directory.
compileDebugAndroidTestSources
compileDebugSources
compileDebugUnitTestSources
compileReleaseSources
compileReleaseUnitTestSources
jar - Assembles a jar archive containing the main classes.
mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests.
testClasses - Assembles test classes.
Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]
Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'AndroidLint'.
components - Displays the components produced by root project 'AndroidLint'. [incubating]
dependencies - Displays all dependencies declared in root project 'AndroidLint'.
dependencyInsight - Displays the insight into a specific dependency in root project 'AndroidLint'.
dependentComponents - Displays the dependent components of components in root project 'AndroidLint'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'AndroidLint'. [incubating]
projects - Displays the sub-projects of root project 'AndroidLint'.
properties - Displays the properties of root project 'AndroidLint'.
tasks - Displays the tasks runnable from root project 'AndroidLint' (some of the displayed tasks may belong to subprojects).
Install tasks
-------------
installDebug - Installs the Debug build.
installDebugAndroidTest - Installs the android (on device) tests for the Debug build.
uninstallAll - Uninstall all applications.
uninstallDebug - Uninstalls the Debug build.
uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build.
uninstallRelease - Uninstalls the Release build.
Verification tasks
------------------
check - Runs all checks.
connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected devices.
connectedCheck - Runs all device checks on currently connected devices.
connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices.
deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers.
deviceCheck - Runs all device checks using Device Providers and Test Servers.
lint - Runs lint on all variants.
lintDebug - Runs lint on the Debug build.
lintRelease - Runs lint on the Release build.
test - Run unit tests for all variants.
testDebugUnitTest - Run unit tests for the debug build.
testReleaseUnitTest - Run unit tests for the release build.
To see all tasks and more detail, run gradlew tasks --all
To see more detail about a task, run gradlew help --task <task>
BUILD SUCCESSFUL
Total time: 1.367 secs
執(zhí)行多個(gè)Task
如果需要先后執(zhí)行多個(gè)Task,例如tasks和clean,將它們依次傳給gradle即可:
./gradlew tasks clean
排除特定Task
使用gradle的-x或--exclude-task參數(shù),可指定執(zhí)行Task時(shí)排除特定Task。例如:
./gradlew build -x check
執(zhí)行SubProject中的Task
如果想執(zhí)行子工程':app'中的Task,可使用Task的完整名執(zhí)行
./gradlew :app:tasks
也可以切換到子工程目錄執(zhí)行,但切換當(dāng)前目錄會(huì)影響Gradle腳本中的相對(duì)路徑,不推薦。
cd app
gradle tasks
Task參數(shù)、查看Task詳細(xì)信息
Task可以定義參數(shù),可在執(zhí)行時(shí)從命令行傳入。例如Gradle內(nèi)建了一個(gè)叫“help”的Task,帶有一個(gè)--task參數(shù),可以用于查看一個(gè)Task的詳細(xì)信息。
查看“tasks”這個(gè)Task的詳細(xì)信息,就可以執(zhí)行命令如下。其中會(huì)顯示一個(gè)Task的名稱、類型、參數(shù)、詳細(xì)介紹、分組等。
$ ./gradlew help --task tasks
:help
Detailed task information for tasks
Path
:tasks
Type
TaskReportTask (org.gradle.api.tasks.diagnostics.TaskReportTask)
Options
--all Show additional tasks and detail.
Description
Displays the tasks runnable from root project 'GradleStudy' (some of the displayed tasks may belong to subprojects).
Group
help
BUILD SUCCESSFUL
Total time: 1.051 secs
一些常用GradleTask
- clean: 清除build目錄編譯生成的文件 (Deletes the build directory.)
- assemble:編譯工程 (Assembles the outputs of this project. [jar])
- build:編譯并測(cè)試工程 (Assembles and tests this project. [assemble, check])
- test:?jiǎn)卧獪y(cè)試等 (Runs the unit tests. [classes, testClasses])
- check:測(cè)試工程,包含test (Runs all checks. [test])
- wrapper:生成GradleWrapper文件 (Generates Gradle wrapper files. [incubating])
- help: 幫助信息 (Displays a help message.)
- tasks:查看Project的所有Task (Displays the tasks runnable from root project 'Xxx'.)
- dependencies:查看Project的依賴 (Displays all dependencies declared in root project 'Xxx'.)
- projects: 查看SubProject (Displays the sub-projects of root project 'Xxx'.)
查看Task依賴樹(shù)
每個(gè)Task都會(huì)依賴若干Task,這些Task又會(huì)依賴別的Task,所有Task就會(huì)形成一個(gè)依賴樹(shù)。
為了更加直觀的學(xué)習(xí),可以在app/build.gradle中添加如下的簡(jiǎn)單腳本,讓Gradle輸出Task的依賴樹(shù)。
方法printDependencies通過(guò)遞歸的方式,輸出每個(gè)Task依賴的Task。afterEvaluate語(yǔ)句塊中,先找到assembleDebug這個(gè)Task,然后調(diào)用printDependencies輸出其依賴樹(shù)。由于Android中有大量Task依賴,打印出所有Task需要很久,所以這里限制了最大遞歸深度為3。
def printDependencies(Task task, String prefix, int depth, int maxDepth) {
println prefix + task.project.name + ':' + task.name
def tasks = task.getTaskDependencies().getDependencies(task)
if (depth < maxDepth - 1) {
tasks.each { t ->
printDependencies(t, prefix + '\t', depth + 1, maxDepth)
}
} else {
if (tasks.size() > 0) {
println prefix + '\t' + "(${tasks.size()} child tasks...)"
}
}
}
afterEvaluate {
println '==============================='
def buildTask = tasks.findByName('assembleDebug')
printDependencies(buildTask, '', 0, 3)
println '==============================='
}
執(zhí)行任意Gradle任務(wù),例如clean,部分輸出內(nèi)容如下。
$ ./gradlew clean
===============================
app:assembleDebug
app:packageDebug
app:processDebugResources
(2 child tasks...)
app:compileDebugJavaWithJavac
(4 child tasks...)
app:mergeDebugAssets
(2 child tasks...)
app:validateSigningDebug
app:transformNativeLibsWithMergeJniLibsForDebug
(3 child tasks...)
app:transformResourcesWithMergeJavaResForDebug
(2 child tasks...)
app:transformClassesWithDexForDebug
(2 child tasks...)
app:compileDebugSources
app:compileDebugNdk
(1 child tasks...)
app:compileDebugJavaWithJavac
(4 child tasks...)
===============================
:clean
:app:clean
BUILD SUCCESSFUL
Total time: 0.975 secs
buildscript與allprojects
在RootProject的build.gradle中,經(jīng)常會(huì)看到buildscript和allprojects兩個(gè)語(yǔ)句塊,并且里面都定義了一些相同的東西。
buildscript,顧名思義,是編譯腳本,也就是說(shuō)編譯一個(gè)工程時(shí)需要的配置,例如常會(huì)看到下面這樣的腳本,表示編譯時(shí)要用到Android Gradle Plugin。
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}
}
allprojects,則用于配置所有project,包括SubProject,這里面的配置的東西,則是工程代碼需要的東西,例如依賴的各種開(kāi)源庫(kù)等。
allprojects {
repositories {
jcenter()
}
}
關(guān)于編譯與Groovy
編譯就是將程序源碼轉(zhuǎn)換成可執(zhí)行文件或中間代碼的過(guò)程。具體到Java,就是將.java代碼文件變成.class或者進(jìn)一步打包成.jar的過(guò)程。
Gradle基于Groovy,Groovy是在Java基礎(chǔ)上擴(kuò)展的腳本語(yǔ)言。Groovy有和解釋型語(yǔ)言一樣的特性,可以直接從源碼運(yùn)行而不需要提前編譯。但實(shí)際運(yùn)行過(guò)程中,也是先轉(zhuǎn)換成Java的class文件,再運(yùn)行在JVM上的。
在buildscript的dependencies中,通過(guò)classpath語(yǔ)句引用一些編譯好的jar包,Gradle在執(zhí)行時(shí)就會(huì)將其下載并加入Java的classpath,其中的class在編譯時(shí)就可以被調(diào)用,運(yùn)行在電腦或云主機(jī)上。
Gradle Plugin
Gradle之所以是個(gè)強(qiáng)大的構(gòu)建系統(tǒng),很重要的一點(diǎn)在于其完善的插件支持。
Gradle內(nèi)建了Java、Groovy等插件,除此之外,還可以在Gradle提供的一整套API基礎(chǔ)上開(kāi)發(fā)插件,實(shí)現(xiàn)各種編譯打包工作。
Gradle Android Plugin
在Android開(kāi)發(fā)編譯時(shí),會(huì)有很多Android相關(guān)的配置,這些都是由Gradle的Android插件實(shí)現(xiàn)的。
在buildscript中,通過(guò)dependencies引入了Gradle Android插件:
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}
}
在app/build.gradle中,通過(guò)apply的方式,應(yīng)用了Android插件:
// 對(duì)于Android Application(APK)
apply plugin: 'com.android.application'
// 對(duì)于Android Library(AAR)
apply plugin: 'com.android.library'
應(yīng)用了Android插件后,即可在app/build.gradle中使用插件定義的Android相關(guān)DSL了:
android {
compileSdkVersion 24
buildToolsVersion '25.0.2'
defaultConfig {
applicationId "com.paincker.lint.demo"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
}
Repositories
很多從Eclipse轉(zhuǎn)到Android Studio的開(kāi)發(fā)者,剛開(kāi)始都對(duì)Gradle自動(dòng)下載依賴包的功能印象深刻。
Gradle的依賴管理完全兼容Maven和Ivy,常使用Maven倉(cāng)庫(kù)來(lái)實(shí)現(xiàn)依賴管理,當(dāng)Library打包完成后上傳到Maven倉(cāng)庫(kù),Gradle則會(huì)從Maven倉(cāng)庫(kù)下載需要的依賴。
Repository就是用來(lái)指定所需要的Maven倉(cāng)庫(kù)。除了常見(jiàn)的jcenter(),mavenCentral(),還可以指定本地搭建的Maven倉(cāng)庫(kù)、指定URL的Maven倉(cāng)庫(kù)等,例如國(guó)內(nèi)一些Maven倉(cāng)庫(kù)鏡像,以及很多公司內(nèi)部私有的Maven倉(cāng)庫(kù)等。
repositories {
jcenter()
mavenCentral()
maven { url 'http://maven.oschina.net/content/groups/public/' }
ivy { url "http://repo.mycompany.com/repo" }
localRepository { dirs 'lib' }
maven {
url "sftp://repo.mycompany.com:22/maven2"
credentials {
username 'user'
password 'password'
}
}
}
Dependencies
Gradle依賴管理官方文檔
https://docs.gradle.org/current/userguide/dependency_management.html
DependencyNotation
DependencyNotation用于描述要依賴的模塊。
外部依賴
通常用group:name:version:classifier@ext的形式表示。其中g(shù)roup通常用包名,name表示實(shí)際的名字,version表示版本,classifier在Android中是ProductFlavor和BuildType的組合(后面會(huì)介紹),ext則表示擴(kuò)展名。
compile "org.gradle.test.classifiers:service:1.0:jdk15@jar"
compile group: 'org.gradle.test.classifiers', name: 'service', version: '1.0', classifier: 'jdk15'
Project依賴
compile project(':someProject')
文件依賴
dependencies {
//declaring arbitrary files as dependencies
compile files('hibernate.jar', 'libs/spring.jar')
//putting all jars from 'libs' onto compile classpath
compile fileTree('libs')
}
參考官方文檔
https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.dsl.DependencyHandler.html
依賴傳遞(transitive)
Gradle依賴項(xiàng)可配置transitive屬性,表示是否遞歸解析此模塊的依賴項(xiàng),默認(rèn)為true。
compile('org.hibernate:hibernate:3.0.5') {
transitive = true
}
依賴樹(shù)查看
每個(gè)模塊都會(huì)依賴若干模塊,這些模塊又分別依賴其他模塊,形成一個(gè)依賴樹(shù)。Gradle提供了名為dependencies的Task,可查看Project的依賴樹(shù),執(zhí)行效果如下(省略了部分輸出)。
$ ./gradlew :app:dependencies
------------------------------------------------------------
Project :app
------------------------------------------------------------
compile - Classpath for compiling the main sources.
+--- com.android.support:appcompat-v7:24.0.0
| +--- com.android.support:support-v4:24.0.0
| | \--- com.android.support:support-annotations:24.0.0
| +--- com.android.support:support-vector-drawable:24.0.0
| | \--- com.android.support:support-v4:24.0.0 (*)
| \--- com.android.support:animated-vector-drawable:24.0.0
| \--- com.android.support:support-vector-drawable:24.0.0 (*)
\--- com.android.support.constraint:constraint-layout:1.0.2
\--- com.android.support.constraint:constraint-layout-solver:1.0.2
Artifact
Artifact可以理解成一個(gè)模塊的具體實(shí)現(xiàn)。一個(gè)依賴項(xiàng)可以包含多個(gè)Artifact,例如依賴項(xiàng)com.demo:mymodule:library:1.0中可以包含多個(gè)不同格式、BuildType的Artifact:
library-1.0-debug.jarlibrary-1.0-release.jarlibrary-1.0-debug.aarlibrary-1.0-release.aar
Module Descriptor、POM文件
Gradle是如何獲取到一個(gè)模塊的依賴項(xiàng)的呢?
在Maven或Ivy倉(cāng)庫(kù)中,模塊的依賴信息并不包含在Artifact文件中,而是通過(guò)ModuleDescriptor文件聲明的。
以阿里的Maven倉(cāng)庫(kù)為例,用瀏覽器打開(kāi)鏈接
http://maven.aliyun.com/nexus/content/groups/public/com/android/tools/build/gradle/2.3.0/
可以看到com.android.tools.build:gradle:2.3.0這個(gè)模塊所包含的文件。其中sources.jar為代碼源文件,pom文件則為ModuleDescriptor。
- gradle-2.3.0-sources.jar
- gradle-2.3.0-sources.jar.md5
- gradle-2.3.0-sources.jar.sha1
- gradle-2.3.0.jar
- gradle-2.3.0.jar.md5
- gradle-2.3.0.jar.sha1
- gradle-2.3.0.pom
- gradle-2.3.0.pom.md5
- gradle-2.3.0.pom.sha1
在Maven倉(cāng)庫(kù)中,模塊的POM文件可以指定默認(rèn)的Artifact,并聲明其依賴項(xiàng);不支持分別聲明多個(gè)Artifact的依賴項(xiàng)。AAR工程配置多版本發(fā)布的時(shí)候,需要考慮這一特性。
If you declare a module dependency, Gradle looks for a module descriptor file (pom.xml or ivy.xml) in the repositories. If such a module descriptor file exists, it is parsed and the artifacts of this module (e.g. hibernate-3.0.5.jar) as well as its dependencies (e.g. cglib) are downloaded. If no such module descriptor file exists, Gradle looks for a file called hibernate-3.0.5.jar to retrieve. In Maven, a module can have one and only one artifact. In Gradle and Ivy, a module can have multiple artifacts. Each artifact can have a different set of dependencies.
多Artifact的依賴處理、Artifact only notation
Gradle在處理依賴時(shí),對(duì)于有多個(gè)Artifact的Maven模塊,可在DependencyNotation中聲明需要的Artifact,沒(méi)有聲明則使用POM文件指定的默認(rèn)版本,POM中也沒(méi)有指定則默認(rèn)使用和module名一致的jar包。
當(dāng)使用“@”指定了所依賴模塊的Artifact,稱為Artifact only notation,此時(shí)Gradle只會(huì)下載對(duì)應(yīng)的Artifact,而不會(huì)下載其依賴,此時(shí)可能就需要設(shè)置transitive屬性。
compile('com.facebook.fresco:fresco:0.10.0@aar') {
transitive = true
}
If no module descriptor file can be found, Gradle by default downloads a jar with the name of the module. But sometimes, even if the repository contains module descriptors, you want to download only the artifact jar, without the dependencies. [11] And sometimes you want to download a zip from a repository, that does not have module descriptors. Gradle provides an artifact only notation for those use cases - simply prefix the extension that you want to be downloaded with '@' sign.
依賴沖突分解
依賴項(xiàng)很多時(shí),依賴項(xiàng)之間經(jīng)常會(huì)發(fā)生沖突。例如多個(gè)SDK分別依賴了不同版本的AppCompat,就可能導(dǎo)致沖突。Gradle提供了一些API可以用來(lái)處理依賴沖突。
常見(jiàn)的依賴沖突解決思路可參考:
Gradle依賴項(xiàng)學(xué)習(xí)總結(jié),dependencies、transitive、force、exclude的使用與依賴沖突解決
http://www.paincker.com/gradle-dependencies
ProductFlavor、BuildType與Build Variant
Android中定義了ProductFlavor和BuildType的DSL。
ProductFlavor
ProductFlavor可以實(shí)現(xiàn)一套代碼編譯成不同的版本,版本之間差異比較小,例如開(kāi)發(fā)版本、測(cè)試版本、線上版本;或是發(fā)布到某些應(yīng)用市場(chǎng)的定制版本(例如需要修改一些資源文件)等。
ProductFlavor中包含了一些應(yīng)用相關(guān)的配置,例如minSdkVersion,versionCode等。下面的代碼,就是在對(duì)默認(rèn)的ProductFlavor做配置。
android {
defaultConfig {
applicationId "com.paincker.gradle.demoapplication"
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
}
可以在ProductFlavors中定義新的Flavor并進(jìn)行配置,覆蓋DefaultProductFlavor中的相應(yīng)配置。
android {
productFlavors {
myflavor {
minSdkVersion 20
}
}
}
ProductFlavor還支持多維度(Multi-flavors),每個(gè)緯度之間可以進(jìn)行組合。例如下面的示例,flavor有abi和version兩個(gè)緯度,最后就會(huì)有6種組合:
- x86-freeapp
- arm-freeapp
- mips-freeapp
- x86-paidapp
- arm-paidapp
- mips-paidapp
android {
...
flavorGroups "abi", "version"
productFlavors {
freeapp {
flavorGroup "version"
...
}
paidapp {
flavorGroup "version"
...
}
x86 {
flavorGroup "abi"
...
}
arm {
flavorGroup "abi"
...
}
mips {
flavorGroup "abi"
...
}
}
}
參考:多定制的變種版本
https://flyouting.gitbooks.io/gradle-plugin-user-guide-cn/content/multi-flavor_variants.html
BuildType
BuildType本身是軟件開(kāi)發(fā)中的通用概念,表示編譯版本。
Android中定義了自己的BuildType接口,其中包含了一些編譯相關(guān)的配置,例如debuggable(是否可調(diào)試)、minifyEnable(是否開(kāi)啟Proguard)等。
可以在buildTypes中配置支持的BuildType如下。即使不做任何配置,默認(rèn)也會(huì)有Debug和Release兩個(gè)BuildType,且分別包含了一套默認(rèn)值,例如Debug的debuggable參數(shù)默認(rèn)為true,而Release的debuggable參數(shù)默認(rèn)為false。
android {
buildTypes {
debug {
}
develop {
debuggable false
minifyEnabled false
}
release {
debuggable false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
BuildVariant
ProductFlavor與BuildType組合,就成為BuildVariant。在前面多緯度Flavor的示例基礎(chǔ)上,6個(gè)Flavor組合2個(gè)BuildType,總共就會(huì)有12種BuildVariant。
每個(gè)Build Variant包含了一個(gè)ProductFlavor和一個(gè)BuildType。BuildType和ProductFlavor中某些配置是重疊的,組合成BuildVariant后,通常會(huì)按優(yōu)先級(jí)處理(一般BuildType優(yōu)先級(jí)更高),或做合并處理。
例如兩者都可以配置簽名signingConfigs,合并成BuildVariant后,會(huì)優(yōu)先取取BuildType中定義的;而對(duì)于配置項(xiàng)proguardFiles,則會(huì)采取合并處理。
具體的合并邏輯,可以參考這個(gè)類中的實(shí)現(xiàn)
com.android.builder.core.VariantConfiguration
BuildConfig
Android開(kāi)發(fā)常用到BuildConfig類,這個(gè)類可在編譯時(shí)生成,用于在代碼中獲取一些編譯相關(guān)的參數(shù),包括是否可以Debug、當(dāng)前BuildType和Flavor名字、VersionCode和VersionName等,例如常會(huì)用BuildConfig.DEBUG判斷是否輸出Log信息。
BuildType配置中提供了一個(gè)buildConfigField方法,可以往BuildConfig中添加自定義字段。
int xxLibraryVersion = 192
android {
buildTypes {
debug {
buildConfigField "int", "XX_LIBRARY_VERSION", xxLibraryVersion
}
release {
buildConfigField "int", "XX_LIBRARY_VERSION", xxLibraryVersion
}
}
}
dependencies {
compile "com.xxx:xx:1.0.${xxLibraryVersion}"
}
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String BUILD_TYPE = "debug";
// Fields from build type: debug
public static final int XX_LIBRARY_VERSION = 192;
}
private void showLibraryInfo() {
String msg = "xx library version is " + BuildConfig.XX_LIBRARY_VERSION;
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
Configurations
在Gradle中,一個(gè)Project可以有多個(gè)Configuration,每個(gè)Configuration有不同的依賴配置。
例如在dependencies中,經(jīng)常用到compile xxx,這里的compile就是一個(gè)Configuration。一些常用的Configuration例如:
- compile:最常用,參與編譯并打包到APK中
- testCompile:用于單元測(cè)試
- androidTestCompile:用于Android自動(dòng)化測(cè)試
- provided:參與編譯但不打包到APK中,類似eclipse中的external-libs
- apk:打包到APK中但不參與編譯,不能在代碼中調(diào)用
考慮到BuildType和ProductFlavor,又會(huì)和上述Configuration組合成新的Configuration,例如:
- compile
- debugCompile
- myflavorCompile
- myflavorDebugCompile
- testCompile
- testDebugCompile
- testMyflavorCompile
- testMyflavorDebugCompile
在運(yùn)行gradle dependencies時(shí),也會(huì)分別顯示每個(gè)Configuration對(duì)應(yīng)的依賴樹(shù),如下(省略了部分輸出)。
./gradlew :app:dependencies
:app:dependencies
------------------------------------------------------------
Project :app
------------------------------------------------------------
androidJacocoAgent - The Jacoco agent to use to get coverage data.
\--- org.jacoco:org.jacoco.agent:0.7.5.201505241946
androidJacocoAnt - The Jacoco ant tasks to use to get execute Gradle tasks.
\--- org.jacoco:org.jacoco.ant:0.7.5.201505241946
+--- org.jacoco:org.jacoco.core:0.7.5.201505241946
| \--- org.ow2.asm:asm-debug-all:5.0.1
+--- org.jacoco:org.jacoco.report:0.7.5.201505241946
| +--- org.jacoco:org.jacoco.core:0.7.5.201505241946 (*)
| \--- org.ow2.asm:asm-debug-all:5.0.1
\--- org.jacoco:org.jacoco.agent:0.7.5.201505241946
androidTestAnnotationProcessor - Classpath for the annotation processor for 'androidTest'.
No dependencies
androidTestApk - Classpath packaged with the compiled 'androidTest' classes.
No dependencies
androidTestCompile - Classpath for compiling the androidTest sources.
No dependencies
androidTestJackPlugin - Classpath for the 'androidTest' Jack plugins.
No dependencies
androidTestProvided - Classpath for only compiling the androidTest sources.
No dependencies
androidTestWearApp - Link to a wear app to embed for object 'androidTest'.
No dependencies
annotationProcessor - Classpath for the annotation processor for 'main'.
No dependencies
apk - Classpath packaged with the compiled 'main' classes.
No dependencies
archives - Configuration for archive artifacts.
No dependencies
compile - Classpath for compiling the main sources.
+--- com.android.support:appcompat-v7:24.0.0
| +--- com.android.support:support-v4:24.0.0
| | \--- com.android.support:support-annotations:24.0.0
| +--- com.android.support:support-vector-drawable:24.0.0
| | \--- com.android.support:support-v4:24.0.0 (*)
| \--- com.android.support:animated-vector-drawable:24.0.0
| \--- com.android.support:support-vector-drawable:24.0.0 (*)
\--- com.android.support.constraint:constraint-layout:1.0.2
\--- com.android.support.constraint:constraint-layout-solver:1.0.2
debugAnnotationProcessor - Classpath for the annotation processor for 'debug'.
No dependencies
debugApk - Classpath packaged with the compiled 'debug' classes.
No dependencies
debugCompile - Classpath for compiling the debug sources.
No dependencies
debugJackPlugin - Classpath for the 'debug' Jack plugins.
No dependencies
debugProvided - Classpath for only compiling the debug sources.
No dependencies
debugWearApp - Link to a wear app to embed for object 'debug'.
No dependencies
default - Configuration for default artifacts.
No dependencies
default-mapping - Configuration for default mapping artifacts.
No dependencies
default-metadata - Metadata for the produced APKs.
No dependencies
jackPlugin - Classpath for the 'main' Jack plugins.
No dependencies
provided - Classpath for only compiling the main sources.
No dependencies
...
SourceSet
Gradle中使用SourceSet管理Java源碼;Android定義了自己的SourceSet,其用法和Gradle類似。
Gradle的SourceSet官方文檔:
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.SourceSet.html
Android的SourceSet官方文檔:
http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.api.AndroidSourceSet.html
默認(rèn)的SourceSet即main,根目錄位于src/main,其中又包括多個(gè)子目錄,例如:
- src/main/java,Java源碼
- src/main/resources,Java資源文件
- src/main/res,Android資源文件
- src/main/assets,Android assets文件
ProductFlavor、BuildType、BuildVariant、test/androidTest,也會(huì)按照一定的形式組合產(chǎn)生SourceSet。
可以配置某個(gè)SourceSet的根目錄,或者指定具體的子目錄(支持多個(gè)目錄),如下:
android {
sourceSets {
myflavor {
res.srcDirs = ['src/main/res', 'src/main/res2']
}
debug.setRoot('src/main')
}
}
使用Gradle的sourceSet可以查看項(xiàng)目中所有的SourceSet。
$ ./gradlew :app:sourceSets
:app:sourceSets
------------------------------------------------------------
Project :app
------------------------------------------------------------
androidTest
-----------
Compile configuration: androidTestCompile
build.gradle name: android.sourceSets.androidTest
Java sources: [app/src/androidTest/java]
Manifest file: app/src/androidTest/AndroidManifest.xml
Android resources: [app/src/androidTest/res]
Assets: [app/src/androidTest/assets]
AIDL sources: [app/src/androidTest/aidl]
RenderScript sources: [app/src/androidTest/rs]
JNI sources: [app/src/androidTest/jni]
JNI libraries: [app/src/androidTest/jniLibs]
Java-style resources: [app/src/androidTest/resources]
androidTestMyflavor
-------------------
Compile configuration: androidTestMyflavorCompile
build.gradle name: android.sourceSets.androidTestMyflavor
Java sources: [app/src/androidTestMyflavor/java]
Manifest file: app/src/androidTestMyflavor/AndroidManifest.xml
Android resources: [app/src/androidTestMyflavor/res]
Assets: [app/src/androidTestMyflavor/assets]
AIDL sources: [app/src/androidTestMyflavor/aidl]
RenderScript sources: [app/src/androidTestMyflavor/rs]
JNI sources: [app/src/androidTestMyflavor/jni]
JNI libraries: [app/src/androidTestMyflavor/jniLibs]
Java-style resources: [app/src/androidTestMyflavor/resources]
debug
-----
Compile configuration: debugCompile
build.gradle name: android.sourceSets.debug
Java sources: [app/src/debug/java]
Manifest file: app/src/debug/AndroidManifest.xml
Android resources: [app/src/debug/res]
Assets: [app/src/debug/assets]
AIDL sources: [app/src/debug/aidl]
RenderScript sources: [app/src/debug/rs]
JNI sources: [app/src/debug/jni]
JNI libraries: [app/src/debug/jniLibs]
Java-style resources: [app/src/debug/resources]
main
----
Compile configuration: compile
build.gradle name: android.sourceSets.main
Java sources: [app/src/main/java]
Manifest file: app/src/main/AndroidManifest.xml
Android resources: [app/src/main/res]
Assets: [app/src/main/assets]
AIDL sources: [app/src/main/aidl]
RenderScript sources: [app/src/main/rs]
JNI sources: [app/src/main/jni]
JNI libraries: [app/src/main/jniLibs]
Java-style resources: [app/src/main/resources]
myflavor
--------
Compile configuration: myflavorCompile
build.gradle name: android.sourceSets.myflavor
Java sources: [app/src/myflavor/java]
Manifest file: app/src/myflavor/AndroidManifest.xml
Android resources: [app/src/myflavor/res]
Assets: [app/src/myflavor/assets]
AIDL sources: [app/src/myflavor/aidl]
RenderScript sources: [app/src/myflavor/rs]
JNI sources: [app/src/myflavor/jni]
JNI libraries: [app/src/myflavor/jniLibs]
Java-style resources: [app/src/myflavor/resources]
myflavorDebug
-------------
Compile configuration: myflavorDebugCompile
build.gradle name: android.sourceSets.myflavorDebug
Java sources: [app/src/myflavorDebug/java]
Manifest file: app/src/myflavorDebug/AndroidManifest.xml
Android resources: [app/src/myflavorDebug/res]
Assets: [app/src/myflavorDebug/assets]
AIDL sources: [app/src/myflavorDebug/aidl]
RenderScript sources: [app/src/myflavorDebug/rs]
JNI sources: [app/src/myflavorDebug/jni]
JNI libraries: [app/src/myflavorDebug/jniLibs]
Java-style resources: [app/src/myflavorDebug/resources]
myflavorRelease
---------------
Compile configuration: myflavorReleaseCompile
build.gradle name: android.sourceSets.myflavorRelease
Java sources: [app/src/myflavorRelease/java]
Manifest file: app/src/myflavorRelease/AndroidManifest.xml
Android resources: [app/src/myflavorRelease/res]
Assets: [app/src/myflavorRelease/assets]
AIDL sources: [app/src/myflavorRelease/aidl]
RenderScript sources: [app/src/myflavorRelease/rs]
JNI sources: [app/src/myflavorRelease/jni]
JNI libraries: [app/src/myflavorRelease/jniLibs]
Java-style resources: [app/src/myflavorRelease/resources]
release
-------
Compile configuration: releaseCompile
build.gradle name: android.sourceSets.release
Java sources: [app/src/release/java]
Manifest file: app/src/release/AndroidManifest.xml
Android resources: [app/src/release/res]
Assets: [app/src/release/assets]
AIDL sources: [app/src/release/aidl]
RenderScript sources: [app/src/release/rs]
JNI sources: [app/src/release/jni]
JNI libraries: [app/src/release/jniLibs]
Java-style resources: [app/src/release/resources]
test
----
Compile configuration: testCompile
build.gradle name: android.sourceSets.test
Java sources: [app/src/test/java]
Java-style resources: [app/src/test/resources]
testDebug
---------
Compile configuration: testDebugCompile
build.gradle name: android.sourceSets.testDebug
Java sources: [app/src/testDebug/java]
Java-style resources: [app/src/testDebug/resources]
testMyflavor
------------
Compile configuration: testMyflavorCompile
build.gradle name: android.sourceSets.testMyflavor
Java sources: [app/src/testMyflavor/java]
Java-style resources: [app/src/testMyflavor/resources]
testMyflavorDebug
-----------------
Compile configuration: testMyflavorDebugCompile
build.gradle name: android.sourceSets.testMyflavorDebug
Java sources: [app/src/testMyflavorDebug/java]
Java-style resources: [app/src/testMyflavorDebug/resources]
testMyflavorRelease
-------------------
Compile configuration: testMyflavorReleaseCompile
build.gradle name: android.sourceSets.testMyflavorRelease
Java sources: [app/src/testMyflavorRelease/java]
Java-style resources: [app/src/testMyflavorRelease/resources]
testRelease
-----------
Compile configuration: testReleaseCompile
build.gradle name: android.sourceSets.testRelease
Java sources: [app/src/testRelease/java]
Java-style resources: [app/src/testRelease/resources]
BUILD SUCCESSFUL
Total time: 1.041 secs
SourceSet的合并、Manifest合并
對(duì)于某個(gè)具體的編譯任務(wù)中某一類源文件,會(huì)根據(jù)一定的優(yōu)先級(jí)與合并規(guī)則,對(duì)多個(gè)SourceSet中的同類源文件進(jìn)行合并得到。
一般情況下,優(yōu)先級(jí)從高到底分別是:
- BuildVariant(src/armFreeappDebug)
- BuildType(src/debug)
- MultiFlavor(src/armFreeapp)
- 每個(gè)單獨(dú)的Flavor(src/arm, src/freeapp)
- sourceSet.main(src/main)
- 依賴中的對(duì)應(yīng)文件(JAR、AAR或SubProject中解析出來(lái)的源文件)
對(duì)于Java類、drawable目錄下的圖片資源文件、layout等,合并措施一般就是同名文件直接覆蓋。
對(duì)于values目錄下的標(biāo)簽類型資源,合并時(shí)會(huì)以每個(gè)標(biāo)簽為最小單元進(jìn)行覆蓋。
<!-- 多個(gè)SourceSet都定義了同名style標(biāo)簽,則高優(yōu)先級(jí)會(huì)直接覆蓋低優(yōu)先級(jí) -->
<!-- src/debug/res/values/xxx.xml 高優(yōu)先級(jí) -->
<style name="txt_main">
<item name="android:textSize">12sp</item>
</style>
<!-- src/main/res/values/yyy.xml 低優(yōu)先級(jí) -->
<style name="txt_main">
<item name="android:textSize">14sp</item>
<item name="android:textColor">@android:color/white</item>
</style>
<!-- 合并后 -->
<style name="txt_main">
<item name="android:textSize">12sp</item>
</style>
而Manifest文件的合并規(guī)則更復(fù)雜一些。具體可參考官方文檔:
https://developer.android.com/studio/build/manifest-merge.html
Android Gradle Task
Android Gradle環(huán)境下,有下面幾個(gè)常見(jiàn)的Task。
- assemble:Gradle內(nèi)建的編譯任務(wù)(生成APK / JAR / AAR)
- test:Gradle內(nèi)建的測(cè)試任務(wù)
- lint:Android定義的Lint檢查任務(wù)
- check:Gradle內(nèi)建的檢查任務(wù),依賴lint、test
- build:Gradle內(nèi)建的Build任務(wù),依賴assemble、check
結(jié)合ProductFlavor、BuildType、BuildVariant,又會(huì)組合成很多Task。
這些Task的依賴關(guān)系示例如下:
app:build
app:check
app:lint
app:test
app:testMyflavor2DebugUnitTest
app:testMyflavor2ReleaseUnitTest
app:testMyflavor1DebugUnitTest
app:testMyflavor1ReleaseUnitTest
app:assemble
app:assembleDebug
app:assembleMyflavor2Debug
app:assembleMyflavor1Debug
app:assembleRelease
app:assembleMyflavor1Release
app:assembleMyflavor2Release
Android Studio/IDEA相關(guān)
在Android Studio/IDEA中開(kāi)發(fā)時(shí),會(huì)在Build Variants窗口選擇指定的Build參數(shù),例如myflavor1Debug。
Sync Project With Gradle Files
當(dāng)修改了gradle文件等情況,會(huì)提示:
Gradle files have changed since last project sync. A project sync may be necessary for the IDE to work properly.
此時(shí)點(diǎn)擊提示欄中的Sync,會(huì)觸發(fā)Gradle同步操作。剛打開(kāi)工程,或者手動(dòng)選擇菜單Tools-Android-Sync Project With Gradle Files或工具欄中的同步按鈕,也會(huì)觸發(fā)同步操作。
在同步過(guò)程中,Gradle會(huì)執(zhí)行很多任務(wù),包括解析并下載所有依賴項(xiàng),解壓AAR、合并SourceSet、生成BuildConfig、R文件(結(jié)果會(huì)輸出到build目錄)等,這樣Android Studio就能加載所有引用的class、jar文件,對(duì)源碼進(jìn)行語(yǔ)法解析,從而代碼也可以正常的跳轉(zhuǎn)了。
通過(guò)GradleConsole窗口,可以看到同步過(guò)程中Gradle所執(zhí)行的Task,其中最主要的是generateMyflavor1DebugSources,即生成源碼的過(guò)程,依賴了prepareMyflavor1DebugDependencies、generateMyflavor1DebugBuildConfig、generateMyflavor1DebugResValues等Task。
:app:preBuild UP-TO-DATE
:app:preMyflavor1DebugBuild UP-TO-DATE
:app:checkMyflavor1DebugManifest
:app:preMyflavor1ReleaseBuild UP-TO-DATE
:app:preMyflavor2DebugBuild UP-TO-DATE
:app:preMyflavor2ReleaseBuild UP-TO-DATE
:app:prepareComAndroidSupportAnimatedVectorDrawable2400Library
:app:prepareComAndroidSupportAppcompatV72400Library
:app:prepareComAndroidSupportConstraintConstraintLayout102Library
:app:prepareComAndroidSupportSupportV42400Library
:app:prepareComAndroidSupportSupportVectorDrawable2400Library
:app:prepareComFacebookFrescoDrawee0100Library
:app:prepareComFacebookFrescoFbcore0100Library
:app:prepareComFacebookFrescoFresco0100Library
:app:prepareComFacebookFrescoImagepipeline0100Library
:app:prepareComFacebookFrescoImagepipelineBase0100Library
:app:prepareMyflavor1DebugDependencies
:app:compileMyflavor1DebugAidl
:app:compileMyflavor1DebugRenderscript
:app:generateMyflavor1DebugBuildConfig
:app:generateMyflavor1DebugResValues
:app:generateMyflavor1DebugResources
:app:mergeMyflavor1DebugResources
:app:processMyflavor1DebugManifest
:app:processMyflavor1DebugResources
:app:generateMyflavor1DebugSources
:app:preMyflavor1DebugAndroidTestBuild UP-TO-DATE
:app:prepareMyflavor1DebugAndroidTestDependencies
:app:compileMyflavor1DebugAndroidTestAidl
:app:processMyflavor1DebugAndroidTestManifest
:app:compileMyflavor1DebugAndroidTestRenderscript
:app:generateMyflavor1DebugAndroidTestBuildConfig
:app:generateMyflavor1DebugAndroidTestResValues
:app:generateMyflavor1DebugAndroidTestResources
:app:mergeMyflavor1DebugAndroidTestResources
:app:processMyflavor1DebugAndroidTestResources
:app:generateMyflavor1DebugAndroidTestSources
:app:mockableAndroidJar UP-TO-DATE
:app:preMyflavor1DebugUnitTestBuild UP-TO-DATE
:app:prepareMyflavor1DebugUnitTestDependencies
BUILD SUCCESSFUL
Total time: 6.425 secs
Run
點(diǎn)擊三角形箭頭時(shí),除了執(zhí)行assembleMyflavor1Debug,還會(huì)執(zhí)行install(將APK安裝至設(shè)備)等Task。
在Android Studio的Run/Debug Configuration窗口中,還可以指定點(diǎn)擊三角箭頭時(shí)要執(zhí)行的Gradle Task。例如可以添加一個(gè)clean操作,每次編譯前先用clean清理build目錄。
AAR多版本發(fā)布
Android開(kāi)發(fā)經(jīng)常會(huì)用到AAR,有時(shí)候希望AAR能支持發(fā)布多個(gè)版本,并在不同的情況下依賴不同版本(包括不同的BuildType和ProductFlavor)。例如主工程依賴xxLibrary,希望Debug版本APK依賴Debug版本的AAR,而Release版本APK依賴Release版本的AAR。
在Android中依賴SubProject或AAR時(shí),如果沒(méi)有特殊配置,AAR的發(fā)布和模塊依賴默認(rèn)均為Release版本。
實(shí)際嘗試主工程依賴子工程,子工程中讀取
BuildConfig.DEBUG的值始終是false,修改Android Studio中子模塊的BuildVariant配置也沒(méi)有效果。
dependencies {
compile project(':xxx_library')
compile 'com.xxx:xxx:1.0.5@aar' {
transitive = true
}
}
可用如下方式配置子模塊或者獨(dú)立AAR工程發(fā)布所有版本:
apply plugin: 'com.android.library'
android {
// 發(fā)布非默認(rèn)版本
publishNonDefault true
// 指定默認(rèn)版本,發(fā)布AAR到Maven時(shí)會(huì)從默認(rèn)版本生成POM依賴配置。
// 不指定會(huì)導(dǎo)致POM無(wú)法正確生成,從而依賴不能傳遞。
defaultPublishConfig "falvorARelease"
productFlavors {
flavorA { }
flavorB { }
}
}
用下面的方式依賴子模塊或已經(jīng)發(fā)布的AAR:
dependencies {
// Debug、Release版本APK,分別依賴Debug、Release版本子模塊
debugCompile project(path: ':xxx', configuration: 'flavorADebug')
releaseCompile project(path: ':xxx', configuration: 'flavorARelease')
// 指定依賴aar版本,并設(shè)置transitive為true
debugCompile('com.xxx:library:1.0.5:flavorADebug@aar') {
transitive = true
}
releaseCompile('com.xxx:library:1.0.5:flavorARelease@aar') {
transitive = true
}
}
本文首發(fā)自我的個(gè)人博客 http://www.paincker.com/android-gradle-basics