我们在上篇文章《Android Gradle使用详解(一) 之 Gradle基础》中介绍了一些关于Gradle的入门相关知识点。本文中会在此基础上对Android工程中Gradle的相关知识进行进一步学习。
我们在通过Android Studio创建一个APP工程时,目录结构如下:
可以看到工程目录中会自动生成一些文件。其中可以看到一些我们熟悉的文件,因为它们跟我们在上篇文章中的Hello World生成的是一样的。有.gradle文件夹、gradle文件夹、build.gradle文件、gradlew文件、 gradlew.bat文件 以及未见过的Settings文件。我们现在就来一步步分析Android Studio创建工程后Gradld的相关知识点。
在Gradle中,根目录定义了一个设置文件Settings,它是用于初始化以及工程树的配置文件。简单说就是为了配置工程的子工程,在Android Studio中就是配置Project和Module。可以看到,我们在刚新建的APP工程New Project后Settings文件只是简单的一行代码:
include ':app'若再执行New Model后,Settings文件会自动变成这样:
include ':app', ':mylibrary'所以,一个子工程只有在Settings文件里配置了Gradle才会识别,才会在构建的时候被包含进去。新建的Model默认是放在跟Project放在根目录中,倘若需要更改存放位置于根目录的sub-project文件平下,也是很简单,还是更改一下Settings文件即可,例如:
include ':app', ':mylibrary' project(':mylibrary').projectDir = new File('sub-project/mylibrary')或者(此方式会在左边Project面板中多出一项sub-project的空的model)
include ':app' include ':sub-project:mylibrary'每个Project都会有一个Build文件,它是Project构建的入口,正如上篇文章中的Hello World示例一样。在Android Studio工程中,若存像上述中有app和mylibrary两个子工程的话,则会出现3个Build文件,它们分别是Root Project的build.gradle和两个Child Project的build.gradle。其中Root Project的build.gradle文件可以对Child Project统一配置,比如应用的插件、依赖的jcenter库等。例如在Root Project的build.gradle文件有这样的配置代码:
allprojects { repositories { google() jcenter() } }也有存在在Root Project的build.gradle中使用subprojects的情况。allprojects和subprojects的区别在于,allprojects是所有模块配置,包括自己,而subprojects只是对Child Project的配置。
Gradle本身内置了很多常用的插件像Java插件,Android Gradle插件就是基于内置的Java插件实现的。插件分二进制插件和脚本插件。使用插件前要先通过Project.apply()方法来应用它。
二进制插件就是实现了org.gradle.api.Plugin接口的插件,它们可以有plugin id,例如应用一个java插件:
apply plugin: 'java'其中,’java’是Java插件的plugin id,它是唯一的。又例如应用android插件,可以看到Child Project的build.gradle文件第一行是:
apply plugin: 'com.android.application'应用脚本插件,其实就是把这个脚本加载进来,它使用的是关键字from,后面紧跟的是一个脚本文件,可以是本地的,也可以是网络的,如果是网络上的话要使用HTTP URL。示例:
build.gradle
apply from:'version.gradle' task hello << { println "APP version: ${versionName},code:${versionCode}" }version.gradle
ext { versionName = '1.0.0' versionCode = 100 }示例中我们把APP的版本号和版本名称单独放在一个脚本文件里。这样我们以后每次APP发版本只需要更改version.gradle文件即可。
若是第三方发布的作为jar的二进制插件,我们在应用时,必须要先在buildscript{}里配置其classpath才能使用。这个就好比Android Gradle插件,它是属于第三方插件,它托管在Jcenter上,所以我们可以看到在Root Project的build.gradle文件发现有这样的配置代码:
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.0.1' } }buildscript{}块是一个在构建项目之前是,为项目进行前期准备和初始化相关配置依赖的地方,配置好所需的依赖后,就可以在Child Project的build.gradle中应用插件,如可见\app\build.gradle中的第一行代码:
apply plugin: 'com.android.application'Android Gradle插件是基于内置的Java插件来实现的第三方插件,所以我们在开始学习Android Gradle插件前,先来了解Java插件。Java插件约定了项目结构,只有我们遵循这些约定,Java插件才能找到我们的Java类、资源进行编译、单元测试类等。默认情况下:
src/main/java 源代码存放目录
src/main/resources 打包资源文件存放目录
src/test/java 单元测试用例存放目录
src/test/resources 单元测试中使用的文件
main和test是Java插件内置的两个源代码集合,如果想自己添加一个如vip的目录可以在build脚本里这么配置:
apply plugin: ‘java’ sourceSets { vip { } }添加一个vip的源代码集合后,我们就可以在src下新建vip/java和vip/resurces目录来存放vip相关的源代码和资源文件。当然默认的文件目录其实也可以修改的,例如:
sourceSets { vip { java { srcDirs ‘src/vip2/java’ } resources.srcDirs = [‘src/ vip2/resources’] // 另外一样配置写法 } }如果要修改main和test两个内置的两个源代码集合的存放目录也是可以的,按照上面vip一样,将其配置一下就可以。
除此之外,SourceSet里的源集属性有:
属性名
类型
描述
name
String
它是只读,比如main
output.classesDir
File
该源集编译后的class文件目录
output.resourcesDir
File
编译后生成的资源目录
compileClasspath
FileCollection
编译后源集时所需的classpath
java
SourceDirectorySet
该源集的Java源文件
java.srcDirs
Set
该源集的Java源文件所在目录
resources
SourceDirectorySet
该源集的资源文件
resources.srcDirs
Set
该源集的资源文件所在目录
我们在开发过程中,不可避免会依赖很多优秀的开源第三方Jar。要想使用这些第三方依赖,就要提前告诉给Gradle配置好如何找到这些依赖。例如上述提到Android Gradle是第三方插件,在使用前必须在repositories中进行配置,告诉Gradle是要去jcenter库搜寻。
repositories
repositories { jcenter() }除jcenter库以外,如若需要引用其它插件或Jar,我们也可以从mavenCentral、ivy、google或者自己搭建的Maven私服库等中搜寻,例如:
repositories { jcenter() maven { url ‘http://www.xxx.com/’ } }dependencies
配置好仓库后,就可以继续配置依赖了。还是例如上述提到Android Gradle是第三方插件,在repositories配置后就可使用dependencies来进行依赖配置:
dependencies { classpath 'com.android.tools.build:gradle:3.0.1' //classpath group: 'com.android.tools.build', name: 'gradle', version: '3.0.1' }除了classpath,还提供了以下的依赖配置:
implementation ( 原 compile) 编译时依赖,依赖不可传递
api ( 原 compile) 编译时依赖,依赖可传递
compileOnly ( 原 provided) 编译时依赖,但代码不能打进包中
runtime 运行时依赖
testImplementation 编译测试用例时依赖,依赖不可传递
testApi 编译测试用例时依赖,依赖可传递
testRuntime 仅仅在测试用例运行时依赖
archives 项目发布构件(JAR包等)依赖
default 默认依赖配置
在项目内部中当Child Project里的app要依赖另一个module时,一般就会在app的build.gradle文件中加入以下的配置:
dependencies { compile project(':mylibrary') }如果依赖的是Jar包,则可以这样:
dependencies { compile files( ‘libs/test.jar’, ‘libs/test2.jar’ ) }或者可以依赖整个文件夹下的所有Jar包:
dependencies { compile fileTree( dir : ‘libs’, include : ‘*.jar’ ) }在Android Studio 3.0开始推荐使用implementation取代了compile。它们的区别是implementation是依赖关系不可能传递,而compile可以。使用implementation可以降低项目依赖的偶合性和提高安全性。例如,项目中有app、module1、module2三个module,它们的依赖关系是这样:app依赖module1,module1依赖module2,如果是使用compile依赖的话是可以做到依赖传递,但是如果使用implementation的话,依赖传递就会失效。
Java插件为我们内置了很多有用的Task,下面列举一些通用的任务:
任务名称
类型
描述
compileJava
JavaCompile
使用javac编译Java源文件
processResource
Copy
把资源文件拷贝到生成的资源文件目录里
classes
Task
组装产生的类和资源文件目录
compileTestJava
JavaCompile
使用javac编译Java源文件
processTestResources
Copy
把测试资源文件复制到生产的资源文件目录里
testClasses
Task
组装产生的测试类和相关资源文件目录
jar
Jar
组装Jar文件
Javadoc
Javadoc
使用javadoc生成Java API文档
test
Test
使用Junit或TestNG运行单元测试
uploadArchives
Upload
上传包含Jar的构建,用archives{}闭包配置
clean
Delete
清理构建生成的目录文件
cleanTaskName
Delete
删除指写任务生成的文件,比如cleanJar删除Jar任务生成的
我们在使用Android Studio新建工程后,便能在Root Project的build.gradle中的最后看到clean任务的配置:
task clean(type: Delete) { delete rootProject.buildDir }对于内置的main和test源集 或者 自己新增的源集(像上面示例的vip)也有一些源集任务:
任务名称
类型
描述
compileXXJava
JavaCompile
使用javac编译指写源集的Java源代码
processXXResources
Copy
把指写源集的资源文件复制到生产文件下的资源目录中
XXClasses
Task
组装给指写源集的类和资源文件目录
Java插件为我们也内置了很多有用的属性,这些属性都被添加到Project中,可以直接使用,比如前面提到的sourceSets,下面列举一些常用的源集属性:
属性名
类型
描述
sourceSets
SourceSetContainer
该Java项目的源集,可以访问和配置源集
sourceCompatibility
JavaVersion
编译Java源文件使用的Java版本
targetCompatibility
JavaVersion
编译生成的类的Java版本
archivesBasenName
String
打包成Jar或Zip文件的名字
manifest
Manifest
用于访问或配置manifest清单文件
libsDir
File
存放生成的类库目录
distsDir
File
存放生成的发布的文件的目录