Android Gradle配置快速入门

说明

本文主要介绍和Gradle关系密切、相对不容易理解的配置,偏重概念介绍。部分内容是Android特有的(例如ProductFlavor),其他内容则是所有Gradle工程都相同或类似的知识。

对于一些常规且相对简单的配置项,例如签名配置SigningConfig,不做具体介绍。而部分比较复杂且不太常用的内容,例如Manifest的具体合并规则,只做简单说明,并给出深入学习的相关链接,读者可自行阅读。

文章主要基于Gradle V3.3 + Android Gradle Plugin V2.3 + Android Studio 2.3,在后续版本升级后部分内容可能会改变。

文中的内容,有些是根据源码分析得到,有些是参考了官方文档,还有些参考了网上的文章。如有不正确的地方,欢迎指正。

关于Gradle DSL的语法原理和开发相关知识,可参考我的另一篇文章

Gradle开发快速入门——DSL语法原理与常用API介绍 http://www.paincker.com/gradle-develop-basics

基本问题

开始看本文前,可以思考下面这些关于Gradle的基本问题。文中会对这些问题进行解释。

  1. settings.gradle有什么作用?
  2. repositories {}语句块的作用?
  3. buildscriptallprojects的区别?
  4. ProductFlavor和BuildType的区别?
  5. 依赖冲突的原因和常见解决思路?
  6. classpath 'com.android.tools.build:gradle:2.2.3',有什么作用?
  7. gradle/wrapper/gradle-wrapper.properties中的这句有什么作用? distributionUrl=https://services.gradle.org/distributions/gradle-2.14.1-all.zip
  8. 命令行中,gradle assemble、gradle assembleDebug、gradle build 的关系?
  9. Android Studio环境下,Gradle Sync操作做了什么工作?

Gradle

Gradle是一个基于Groovy语言的强大的构建系统,Groovy则是在Java基础上扩展的、运行在JVM上的一种脚本语言。

通过丰富的插件扩展,Gradle可以支持Java、JavaWeb、Groovy、Android等工程的编译,同时可以很方便的从Maven、Ant等迁移过来。

C系列语言也有相应的Gradle插件,但Gradle支持最好的还是Java系列语言。

Gradle也是一个命令行可执行程序,可从官网下载Gradle,可执行文件位于bin/gradle

执行Gradle任务的过程,主要就是在运行Java/Groovy代码。编译期间如果有代码抛出了异常,就会中断编译过程。

在Android Studio中开发时,编译就是基于Gradle实现的。Android Studio中内置了Gradle。

Gradle官网 https://gradle.org/

Gradle Wrapper

用IDEA/Android Studio创建基于Gradle的工程时,默认会在工程根目录创建GradleWrapper,包括gradlew可执行脚本和gradle/wrapper文件夹,其中指定了和工程配套的gradle版本。

在工程根目录下直接执行./gradlew,会自动将参数传给wrapper指定版本的gradle,执行对应的命令;如果本机还没有该版本的gradle,则会先自动下载。

工程配置和Gradle版本通常需要对应,不正确的Gradle版本可能无法正常编译工程,因此推荐使用GradleWrapper执行Gradle命令。

gradle/wrapper/gradle-wrapper.properties文件,指定了gradle版本、下载地址、下载的文件存放位置(Mac系统中默认在~/.gradle/wrapper/dists目录)。此文件内容示例:

1
2
3
4
5
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中,可通过Preferences - Build, Execution, Deployment - Gradle,设置Project-level settings中Use default gradle wrapper,指定Android Studio使用工程配置的Gradle Wrapper。

DSL、DSL Reference

Gradle使用Groovy语言封装了一整套API,通常把这套API称为DSL(Domain-Specific Languages,领域特定语言)。

通常在我们配置Gradle编译参数时,所写的gradle脚本从形式上来看,像是一门有着特殊语法格式的语言。

Gradle封装的DSL,按照固定格式用很简单的语法就能实现很复杂的配置,大大简化了配置工作。另一方面,也正是由于封装的非常完善,想深入学习Gradle,会感觉无从下手。

可以通过DSL Reference文档查看Gradle DSL支持的语法配置项。例如:

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/

关于Gradle DSL的语法原理和开发相关知识,可参考我的另一篇文章

Gradle开发快速入门——DSL语法原理与常用API介绍 http://www.paincker.com/gradle-develop-basics

Project、RootProject、SubProject (Module)

Project是Gradle中的基本概念之一,即一个工程。一个工程可以包含多个SubProject,也称为Module,最顶层的工程也称为RootProject。

一个标准的Android工程,文件结构如下。

  • 每个build.gradle对应一个Project,最外层的是RootProject,里面的app是SubProject。
  • settings.gradle不是必须的,一般在包含子工程时就需要用这个文件指定,即我们通常所见的include ':app'脚本。
  • 这里的':app'就是子工程的名字,通常和文件夹名称对应。
1
2
3
4
settings.gradle
build.gradle
app
build.gradle

StartParameter

Gradle执行时有一些称为StartParameter的参数,StartParameter可在命令行设置,可通过gradle --help查看。例如:

  1. --quiet,执行过程中,只显示Error级别的Log。
  2. --stacktrace,执行过程中,输出所有Exception的stacktrace。
  3. --full-stacktrace,执行过程中,输出所有Exception的完整stacktrace。
  4. --no-daemon,不使用Deamon。Deamon是用于加速Gradle执行的后台进程,有些情况下使用Deamon会有问题(可参考 https://docs.gradle.org/current/userguide/gradle_daemon.html
  5. --offline,离线模式,不使用网络资源。

在命令行可通过-P参数传入projectProperties,并在Gradle脚本中获取

1
2
# 命令行传入projectProperties
./gradlew clean -Pkey=value
1
2
// gradle脚本中获取projectProperties
print gradle.startParameter.projectProperties.get('key')

还可以通过-D参数传入systemPropertiesArgs,并在Gradle脚本中获取

1
2
# 命令行传入systemPropertiesArgs
./gradlew clean -Dkey=value
1
2
// gradle脚本中获取systemPropertiesArgs
print gradle.startParameter.systemPropertiesArgs.get('key')

gradle.properties

Properties文件格式可由java.util.Properties解析,包含若干键值对,类似HashMap<String,String>

Gradle运行时会自动读取gradle.properties文件并引用其中的属性。有多个位置可以放gradle.properties文件,按优先级从低到高如下:

  • Project所在目录(即build.gradle所在目录),包括RootProject和SubProject
  • GradleHome目录(Mac中默认为~/gradle
  • 通过gradle命令行-D参数指定的Property

在gradle.properties文件中,一些保留Key可用于配置Gradle运行环境,例如org.gradle.daemon用于设置GradleDeamon,org.gradle.logging.level用于设置Gradle的Log级别等。

详情可参考 https://docs.gradle.org/current/userguide/build_environment.html

除了保留Key以外,其他Key都可以作为变量用于配置工程。例如在Project目录的gradle.properties中统一定义Support包的版本号,然后在build.gradle中使用定义的变量如下。

1
SUPPORT_LIBRARY_VERSION=23.4.0
1
2
3
4
5
6
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(任务)的形式组织每一步操作,每个Task执行一个原子操作(例如把Java编译成class文件、把class打成jar/dex文件、APK签名等)。

每个Project包含若干Task,Task之间存在依赖关系,执行一个Task前,会先执行它所依赖的Task。

每个Task有自己的名字(例如'assemble'),结合其所属Project的名字(例如':app'),可以组成完整名(例如':app:assemble')。

Gradle内建了一个名为tasks的Task,可以列举Project中的所有Task。

执行Task,查看Project中的所有Task

执行Task时,直接把Task名称传给gradle即可。

如果下载了Gradle并配置了环境变量,则可在工程根目录执行:

1
gradle tasks

更推荐的做法,是在工程根目录下调用GradleWrapper执行:

1
./gradlew tasks

执行结果如下(省略了部分输出):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
$ ./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

执行多个Task

如果需要先后执行多个Task,例如tasks和clean,将它们依次传给gradle即可:

1
./gradlew tasks clean

排除特定Task

使用gradle的-x--exclude-task参数,可指定执行Task时排除特定Task。例如:

1
./gradlew build -x check

执行SubProject中的Task

如果想执行子工程':app'中的Task,可使用Task的完整名执行

1
./gradlew :app:tasks

也可以切换到子工程目录执行,但切换当前目录会影响Gradle脚本中的相对路径,不推荐。

1
2
cd app
gradle tasks

Task参数、查看Task详细信息

Task可以定义参数,可在执行时从命令行传入。例如Gradle内建了一个叫“help”的Task,带有一个--task参数,可以用于查看一个Task的详细信息。

查看“tasks”这个Task的详细信息,就可以执行命令如下。其中会显示一个Task的名称、类型、参数、详细介绍、分组等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ ./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:编译并测试工程 (Assembles and tests this project. [assemble, check])

  • test:单元测试等 (Runs the unit tests. [classes, testClasses])

  • check:测试工程,包含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依赖树

每个Task都会依赖若干Task,这些Task又会依赖别的Task,所有Task就会形成一个依赖树。

为了更加直观的学习,可以在app/build.gradle中添加如下的简单脚本,让Gradle输出Task的依赖树。

方法printDependencies通过递归的方式,输出每个Task依赖的Task。afterEvaluate语句块中,先找到assembleDebug这个Task,然后调用printDependencies输出其依赖树。由于Android中有大量Task依赖,打印出所有Task需要很久,所以这里限制了最大递归深度为3。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 '==============================='
}

执行任意Gradle任务,例如clean,部分输出内容如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ ./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中,经常会看到buildscript和allprojects两个语句块,并且里面都定义了一些相同的东西。

buildscript,顾名思义,是编译脚本,也就是说编译一个工程时需要的配置,例如常会看到下面这样的脚本,表示编译时要用到Android Gradle Plugin。

1
2
3
4
5
6
7
8
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}
}

allprojects,则用于配置所有project,包括SubProject,这里面的配置的东西,则是工程代码需要的东西,例如依赖的各种开源库等。

1
2
3
4
5
allprojects {
repositories {
jcenter()
}
}

关于编译与Groovy

编译就是将程序源码转换成可执行文件或中间代码的过程。具体到Java,就是将.java代码文件变成.class或者进一步打包成.jar的过程。

Gradle基于Groovy,Groovy是在Java基础上扩展的脚本语言。Groovy有和解释型语言一样的特性,可以直接从源码运行而不需要提前编译。但实际运行过程中,也是先转换成Java的class文件,再运行在JVM上的。

在buildscript的dependencies中,通过classpath语句引用一些编译好的jar包,Gradle在执行时就会将其下载并加入Java的classpath,其中的class在编译时就可以被调用,运行在电脑或云主机上。

Gradle Plugin

Gradle之所以是个强大的构建系统,很重要的一点在于其完善的插件支持。

Gradle内建了Java、Groovy等插件,除此之外,还可以在Gradle提供的一整套API基础上开发插件,实现各种编译打包工作。

Gradle Android Plugin

在Android开发编译时,会有很多Android相关的配置,这些都是由Gradle的Android插件实现的。

在buildscript中,通过dependencies引入了Gradle Android插件:

1
2
3
4
5
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}
}

在app/build.gradle中,通过apply的方式,应用了Android插件:

1
2
3
4
5
// 对于Android Application(APK)
apply plugin: 'com.android.application'

// 对于Android Library(AAR)
apply plugin: 'com.android.library'

应用了Android插件后,即可在app/build.gradle中使用插件定义的Android相关DSL了:

1
2
3
4
5
6
7
8
9
10
11
12
android {
compileSdkVersion 24
buildToolsVersion '25.0.2'

defaultConfig {
applicationId "com.paincker.lint.demo"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
}

Repositories

很多从Eclipse转到Android Studio的开发者,刚开始都对Gradle自动下载依赖包的功能印象深刻。

Gradle的依赖管理完全兼容Maven和Ivy,常使用Maven仓库来实现依赖管理,当Library打包完成后上传到Maven仓库,Gradle则会从Maven仓库下载需要的依赖。

Repository就是用来指定所需要的Maven仓库。除了常见的jcenter(),mavenCentral(),还可以指定本地搭建的Maven仓库、指定URL的Maven仓库等,例如国内一些Maven仓库镜像,以及很多公司内部私有的Maven仓库等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的形式表示。其中group通常用包名,name表示实际的名字,version表示版本,classifier在Android中是ProductFlavor和BuildType的组合(后面会介绍),ext则表示扩展名。

1
2
3
compile "org.gradle.test.classifiers:service:1.0:jdk15@jar"

compile group: 'org.gradle.test.classifiers', name: 'service', version: '1.0', classifier: 'jdk15'

Project依赖

1
compile project(':someProject')

文件依赖

1
2
3
4
5
6
7
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依赖项可配置transitive属性,表示是否递归解析此模块的依赖项,默认为true。

1
2
3
compile('org.hibernate:hibernate:3.0.5') {
transitive = true
}

依赖树查看

每个模块都会依赖若干模块,这些模块又分别依赖其他模块,形成一个依赖树。Gradle提供了名为dependencies的Task,可查看Project的依赖树,执行效果如下(省略了部分输出)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ ./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可以理解成一个模块的具体实现。一个依赖项可以包含多个Artifact,例如依赖项com.demo:mymodule:library:1.0中可以包含多个不同格式、BuildType的Artifact:

  • library-1.0-debug.jar
  • library-1.0-release.jar
  • library-1.0-debug.aar
  • library-1.0-release.aar

Module Descriptor、POM文件

Gradle是如何获取到一个模块的依赖项的呢?

在Maven或Ivy仓库中,模块的依赖信息并不包含在Artifact文件中,而是通过ModuleDescriptor文件声明的。

以阿里的Maven仓库为例,用浏览器打开链接 http://maven.aliyun.com/nexus/content/groups/public/com/android/tools/build/gradle/2.3.0/

可以看到com.android.tools.build:gradle:2.3.0这个模块所包含的文件。其中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仓库中,模块的POM文件可以指定默认的Artifact,并声明其依赖项;不支持分别声明多个Artifact的依赖项。AAR工程配置多版本发布的时候,需要考虑这一特性。

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在处理依赖时,对于有多个Artifact的Maven模块,可在DependencyNotation中声明需要的Artifact,没有声明则使用POM文件指定的默认版本,POM中也没有指定则默认使用和module名一致的jar包。

当使用“@”指定了所依赖模块的Artifact,称为Artifact only notation,此时Gradle只会下载对应的Artifact,而不会下载其依赖,此时可能就需要设置transitive属性。

1
2
3
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.

依赖冲突分解

依赖项很多时,依赖项之间经常会发生冲突。例如多个SDK分别依赖了不同版本的AppCompat,就可能导致冲突。Gradle提供了一些API可以用来处理依赖冲突。

常见的依赖冲突解决思路可参考:

Gradle依赖项学习总结,dependencies、transitive、force、exclude的使用与依赖冲突解决 http://www.paincker.com/gradle-dependencies

ProductFlavor、BuildType与Build Variant

Android中定义了ProductFlavor和BuildType的DSL。

ProductFlavor

ProductFlavor可以实现一套代码编译成不同的版本,版本之间差异比较小,例如开发版本、测试版本、线上版本;或是发布到某些应用市场的定制版本(例如需要修改一些资源文件)等。

ProductFlavor中包含了一些应用相关的配置,例如minSdkVersion,versionCode等。下面的代码,就是在对默认的ProductFlavor做配置。

1
2
3
4
5
6
7
8
9
android {
defaultConfig {
applicationId "com.paincker.gradle.demoapplication"
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
}

可以在ProductFlavors中定义新的Flavor并进行配置,覆盖DefaultProductFlavor中的相应配置。

1
2
3
4
5
6
7
android {
productFlavors {
myflavor {
minSdkVersion 20
}
}
}

ProductFlavor还支持多维度(Multi-flavors),每个纬度之间可以进行组合。例如下面的示例,flavor有abi和version两个纬度,最后就会有6种组合:

  • x86-freeapp
  • arm-freeapp
  • mips-freeapp
  • x86-paidapp
  • arm-paidapp
  • mips-paidapp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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本身是软件开发中的通用概念,表示编译版本。

Android中定义了自己的BuildType接口,其中包含了一些编译相关的配置,例如debuggable(是否可调试)、minifyEnable(是否开启Proguard)等。

可以在buildTypes中配置支持的BuildType如下。即使不做任何配置,默认也会有Debug和Release两个BuildType,且分别包含了一套默认值,例如Debug的debuggable参数默认为true,而Release的debuggable参数默认为false。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的示例基础上,6个Flavor组合2个BuildType,总共就会有12种BuildVariant。

每个Build Variant包含了一个ProductFlavor和一个BuildType。BuildType和ProductFlavor中某些配置是重叠的,组合成BuildVariant后,通常会按优先级处理(一般BuildType优先级更高),或做合并处理。

例如两者都可以配置签名signingConfigs,合并成BuildVariant后,会优先取取BuildType中定义的;而对于配置项proguardFiles,则会采取合并处理。

具体的合并逻辑,可以参考这个类中的实现 com.android.builder.core.VariantConfiguration

BuildConfig

Android开发常用到BuildConfig类,这个类可在编译时生成,用于在代码中获取一些编译相关的参数,包括是否可以Debug、当前BuildType和Flavor名字、VersionCode和VersionName等,例如常会用BuildConfig.DEBUG判断是否输出Log信息。

BuildType配置中提供了一个buildConfigField方法,可以往BuildConfig中添加自定义字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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}"
}
1
2
3
4
5
6
7
8
9
10
11
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中,一个Project可以有多个Configuration,每个Configuration有不同的依赖配置。

例如在dependencies中,经常用到compile xxx,这里的compile就是一个Configuration。一些常用的Configuration例如:

  • compile:最常用,参与编译并打包到APK中
  • testCompile:用于单元测试
  • androidTestCompile:用于Android自动化测试
  • provided:参与编译但不打包到APK中,类似eclipse中的external-libs
  • apk:打包到APK中但不参与编译,不能在代码中调用

考虑到BuildType和ProductFlavor,又会和上述Configuration组合成新的Configuration,例如:

  • compile
  • debugCompile
  • myflavorCompile
  • myflavorDebugCompile
  • testCompile
  • testDebugCompile
  • testMyflavorCompile
  • testMyflavorDebugCompile

在运行gradle dependencies时,也会分别显示每个Configuration对应的依赖树,如下(省略了部分输出)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
./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

默认的SourceSet即main,根目录位于src/main,其中又包括多个子目录,例如:

  • src/main/java,Java源码
  • src/main/resources,Java资源文件
  • src/main/res,Android资源文件
  • src/main/assets,Android assets文件

ProductFlavor、BuildType、BuildVariant、test/androidTest,也会按照一定的形式组合产生SourceSet。

可以配置某个SourceSet的根目录,或者指定具体的子目录(支持多个目录),如下:

1
2
3
4
5
6
7
8
android {
sourceSets {
myflavor {
res.srcDirs = ['src/main/res', 'src/main/res2']
}
debug.setRoot('src/main')
}
}

使用Gradle的sourceSet可以查看项目中所有的SourceSet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
$ ./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合并

对于某个具体的编译任务中某一类源文件,会根据一定的优先级与合并规则,对多个SourceSet中的同类源文件进行合并得到。

一般情况下,优先级从高到底分别是:

  • BuildVariant(src/armFreeappDebug)
  • BuildType(src/debug)
  • MultiFlavor(src/armFreeapp)
  • 每个单独的Flavor(src/arm, src/freeapp)
  • sourceSet.main(src/main)
  • 依赖中的对应文件(JAR、AAR或SubProject中解析出来的源文件)

对于Java类、drawable目录下的图片资源文件、layout等,合并措施一般就是同名文件直接覆盖。

对于values目录下的标签类型资源,合并时会以每个标签为最小单元进行覆盖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 多个SourceSet都定义了同名style标签,则高优先级会直接覆盖低优先级 -->
<!-- src/debug/res/values/xxx.xml 高优先级 -->
<style name="txt_main">
<item name="android:textSize">12sp</item>
</style>

<!-- src/main/res/values/yyy.xml 低优先级 -->
<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文件的合并规则更复杂一些。具体可参考官方文档:

https://developer.android.com/studio/build/manifest-merge.html

Android Gradle Task

Android Gradle环境下,有下面几个常见的Task。

  • assemble:Gradle内建的编译任务(生成APK / JAR / AAR)
  • test:Gradle内建的测试任务
  • lint:Android定义的Lint检查任务
  • check:Gradle内建的检查任务,依赖lint、test
  • build:Gradle内建的Build任务,依赖assemble、check

结合ProductFlavor、BuildType、BuildVariant,又会组合成很多Task。

这些Task的依赖关系示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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相关

在Android Studio/IDEA中开发时,会在Build Variants窗口选择指定的Build参数,例如myflavor1Debug。

Sync Project With Gradle Files

当修改了gradle文件等情况,会提示:

Gradle files have changed since last project sync. A project sync may be necessary for the IDE to work properly.

此时点击提示栏中的Sync,会触发Gradle同步操作。刚打开工程,或者手动选择菜单Tools-Android-Sync Project With Gradle Files或工具栏中的同步按钮,也会触发同步操作。

在同步过程中,Gradle会执行很多任务,包括解析并下载所有依赖项,解压AAR、合并SourceSet、生成BuildConfig、R文件(结果会输出到build目录)等,这样Android Studio就能加载所有引用的class、jar文件,对源码进行语法解析,从而代码也可以正常的跳转了。

通过GradleConsole窗口,可以看到同步过程中Gradle所执行的Task,其中最主要的是generateMyflavor1DebugSources,即生成源码的过程,依赖了prepareMyflavor1DebugDependencies、generateMyflavor1DebugBuildConfig、generateMyflavor1DebugResValues等Task。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
: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

点击三角形箭头时,除了执行assembleMyflavor1Debug,还会执行install(将APK安装至设备)等Task。

在Android Studio的Run/Debug Configuration窗口中,还可以指定点击三角箭头时要执行的Gradle Task。例如可以添加一个clean操作,每次编译前先用clean清理build目录。

AAR多版本发布

Android开发经常会用到AAR,有时候希望AAR能支持发布多个版本,并在不同的情况下依赖不同版本(包括不同的BuildType和ProductFlavor)。例如主工程依赖xxLibrary,希望Debug版本APK依赖Debug版本的AAR,而Release版本APK依赖Release版本的AAR。

在Android中依赖SubProject或AAR时,如果没有特殊配置,AAR的发布和模块依赖默认均为Release版本。

实际尝试主工程依赖子工程,子工程中读取BuildConfig.DEBUG的值始终是false,修改Android Studio中子模块的BuildVariant配置也没有效果。

1
2
3
4
5
6
dependencies {
compile project(':xxx_library')
compile 'com.xxx:xxx:1.0.5@aar' {
transitive = true
}
}

可用如下方式配置子模块或者独立AAR工程发布所有版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apply plugin: 'com.android.library'

android {
// 发布非默认版本
publishNonDefault true
// 指定默认版本,发布AAR到Maven时会从默认版本生成POM依赖配置。
// 不指定会导致POM无法正确生成,从而依赖不能传递。
defaultPublishConfig "falvorARelease"

productFlavors {
flavorA { }
flavorB { }
}
}

用下面的方式依赖子模块或已经发布的AAR:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dependencies {

// Debug、Release版本APK,分别依赖Debug、Release版本子模块
debugCompile project(path: ':xxx', configuration: 'flavorADebug')
releaseCompile project(path: ':xxx', configuration: 'flavorARelease')

// 指定依赖aar版本,并设置transitive为true
debugCompile('com.xxx:library:1.0.5:flavorADebug@aar') {
transitive = true
}
releaseCompile('com.xxx:library:1.0.5:flavorARelease@aar') {
transitive = true
}
}