![](https://img.haomeiwen.com/i1797490/3e03f457ee44216a.png)
目录
![](https://img.haomeiwen.com/i1797490/ed59cdcbb95521d2.png)
1.Gradle简介
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。
Gradle 是基于 Groovy 语言的,他们之间的关系就像《Android 群英传:神兵利器》中说的:Groovy 对于 Gradle,就好比 Java 对于 Android。
Groovy
Groovy的基本语法这里不做阐述,它对Java代码进行了扩展,完全可以使用Java代码,这里简单介绍一下闭包的用法,方便下面的代码阅读。
闭包Closure
{ 参数 -> 代码 }
{ String name, int age ->
println name
println age
}
在groovy中调用方法时,“()”可以省略
/** 定义一个方法,参数为闭包 */
def project(Closure configureClosure){
...........
}
//调用方法,()省略,方法名后面跟的是要传入的参数
project {
}
Gradle的构建脚本生命周期
![](https://img.haomeiwen.com/i1797490/179bbae1ba96d5af.png)
![](https://img.haomeiwen.com/i1797490/a71c38013cefc518.png)
对应的方法
/** 配置阶段开始前的执行 */
this.beforeEvaluate {
println '配置开始'
}
/** 配置阶段完成以后执行*/
this.afterEvaluate {
println '配置完成,开始执行'
}
/** gradle执行完毕后执行 */
this.gradle.buildFinished {
println '执行完毕'
}
在初始化阶段会执行settings.gradle,所以可以在该文件中监听初始化开始。
![](https://img.haomeiwen.com/i1797490/9f32de1d04cbda03.png)
2.Project
2.1Project简介
在Gradle中每个待编译的工程都是一个Project(每个工程的build.gradle对应一个Project对象),每个Project在构建的时候都包含一系列Task,这些Task中很多又是Gradle的插件默认支持的。每一个Project对象和build.gradle一一对应。
![](https://img.haomeiwen.com/i1797490/c9960a618ce755b5.png)
2.2Project相关API
/** 获取所有的Project */
this.getAllprojects()
/** 获取跟节点的Project */
this.getRootProject()
/** 获取当前节点的子节点Project */
this.getSubprojects()
/** 获取当前节点的父节点Project */
this.getParent()
/** 直接获取指定的Project */
Project project(String path);
Project project(String path, Closure configureClosure);
eg:
project('app') { Project project ->
//通过参数project就可以直接配置project了,比如指定版本号,分组,应用插件,依赖等一系列操作
println project.name
apply plugin: 'com.android.application'
dependencies {}
android {}
}
/** 配置当前节点工程和其所有子节点工程 */
allprojects {
}
/** 配置当前节点d的所有子节点工程 */
subprojects {
}
2.3属性相关API
默认提供的属性,查看Project 源码
@HasInternalProtocol
public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
/**
* The default project build file name.
*/
String DEFAULT_BUILD_FILE = "build.gradle"; // 默认的构建文件
/**
* The hierarchy separator for project and task path names.
*/
String PATH_SEPARATOR = ":"; //默认的文件分隔符
/**
* The default build directory name.
*/
String DEFAULT_BUILD_DIR_NAME = "build"; //默认的输出文件
String GRADLE_PROPERTIES = "gradle.properties"; //扩展属性文件
String SYSTEM_PROP_PREFIX = "systemProp";
String DEFAULT_VERSION = "unspecified";
String DEFAULT_STATUS = "release";
//省略其他代码
}
Project默认提供的属性不过,下面我们可以通过扩展属性来增加Projec的属性。
自定义扩展属性
- 方式一:
//定义扩展属性
ext{
/*扩展的的属性*/
compileSdkVersion = 25
}
//调用
this.compileSdkVersion
- 方式二:
在工程提供的gradle.properties文件中直接定义,只能以key-value的方法定义。
android.useDeprecatedNdk = true
isLib = false
compileSdkVersion = 25
2.4文件相关API
![](https://img.haomeiwen.com/i1797490/820695b9c869e6dc.png)
路径相关
/** 获取根工程的路径 */
this.getRootDir().absolutePath
/** 获取当前project 的路径 */
this.getProjectDir().absolutePath
/** 获取Build文件夹的路径 */
this.getBuildDir().absolutePath
文件定位
/** 在当前的Project下寻找指定的文件 */
File file(Object path);
def file = file('build.gradle')
println file.text //打印文件的内容
文件拷贝
/** 拷贝文件,参数为闭包 */
WorkResult copy(Closure closure);
copy {
//将输出的apk拷贝到指定的文件夹中
from file('build/outputs/apk/')
into getRootProject().getBuildDir().path + '/apk/'
exclude{
//可以去除不想拷贝的文件
}
rename {
//可以对文件重命名
}
}
文件树遍历
ConfigurableFileTree fileTree(Object baseDir, Closure configureClosure);
fileTree('build/outputs/apk/'){ fileTree fileTree ->
fileTree.visit { FileVisitDetails details ->
println details.file.name //输出指定文件夹下所有的文件名
}
}
2.5依赖相关API
/** 调用buildscript方法配置我们的依赖 */
buildscript { ScriptHandler scriptHandler ->
/** 配置工程的仓库地址 */
scriptHandler.repositories { RepositoryHandler repositoryHandler ->
repositoryHandler.maven {}
repositoryHandler.mavenCentral()
repositoryHandler.mavenLocal()
repositoryHandler.jcenter()
repositoryHandler.ivy {}
}
/** 配置工程的“插件”依赖地址(Gradle本身的依赖) */
scriptHandler.dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.1.0'
}
}
在闭包中,参数是可以省略的,这里为了更直观的看出调用的具体是谁的方法,所以写了参数。
/** 为我们的应用程序配置依赖 */
dependencies {
//依赖文件树
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:25.+'
//依赖project
compile project(':EaseUI_CN')
compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'
compile 'com.orhanobut:logger:2.1.0'
}
解决依赖冲突
当我们依赖的库中,如果某些库都引入了一个相同的包或者库,并且版本不一致,这样就会导致依赖冲突。我们通过配置可以删除指定库中的依赖。
compile(rootProject.ext.dependence.libAutoScrollViewPager) {
exclude module: 'support-v4' //排除依赖,单个
exclude group: 'com.android.support' //排除该组下所有的依赖(排除support下的所有包的依赖)
transitive false //禁止传递依赖
}
exclude 后面跟key-value ; key:表示类型 value:表示具体的内容
传递依赖:我们依赖的库中可能会依赖别的三方库,如果传递依赖为true:表示我们可以使用三方库所依赖的库中的东西。transitive 默认值就是false。
provided依赖
//Tinker相关依赖
compile(rootProject.ext.dependence.libTinker) {
changing = true //每次都从服务端拉取
}
provided(rootProject.ext.dependence.libTinkerAndroid) {
changing = true
}
通过compile依赖的方法,最终打包的时候会把所以来的库中的类和资源打包到apk中。而通过provided依赖的话资源不会被打包到apk中,只是在编译的时候会读取类和资源。
provided的使用场景
provided(rootProject.ext.dependence.libTinkerAndroid)
像这种依赖,libTinkerAndroid
的作用只是生成对应的Application
文件的,所以在编译的时候生成Application
文件后,就没有用了,所以不需要打包到APK中。
第二种情景是:假设我们的库工程中引入了okhttp3.1
,而我们的主工程依赖该库工程。那么我们的主工程就可以使用provided方法依赖okhttp3.1
,在编译的时候通过。不用再重复依赖了。
3.Task
3.1创建Task
方式一:
Task task(String name, Closure configureClosure);
task MyTask {
println 'is MyTask'
}
方式二:
//通过TaskContainer的create方法
this.tasks.create(name:'MyTask'){
println 'is MyTask'
}
3.2配置Task
配置分组和描述信息。
task MyTask(group:'TestTask',description:'task study'){
println 'is MyTask'
}
//通过TaskContainer的create方法
this.tasks.create(name:'MyTask'){
setGroup('TestTask')
setDescription('task study')
println 'is MyTask'
}
![](https://img.haomeiwen.com/i1797490/7629ad1adefd9eba.png)
相同组名会被放在同一文件夹下,便于管理。
让Task的代码执行在执行阶段
task MyTask(group: 'TestTask', description: 'task study') {
doFirst {//执行开始的时候
}
doLast{//执行结束的时候
}
}
MyTask.doFirst{
}
通过doFirst 或者doLast可以让代码执行在执行阶段,只有Task才能让代码执行在执行阶段。
task MyTask << {
println 'MyTask' // << 等价于doLast{}
}
3.3Task的执行顺序
![](https://img.haomeiwen.com/i1797490/27f68637b930d3b4.png)
依赖方式指定:
task taskA {
doLast {
println 'taskA'
}
}
task taskB {
doLast {
println 'taskB'
}
}
task taskC(dependsOn: [taskA, taskB]) {
doLast {
println 'taskC'
}
}
//或者
taskC.dependsOn(taskA, taskB)
taskC依赖taskA和taskB,所以taskC在两者之后执行
动态指定
task MyTask {
//依赖所有名字以lib开始的task
dependsOn this.tasks.findAll {
task -> return task.name.startsWith('lib')
}
}
通过输入输出指定顺序
![](https://img.haomeiwen.com/i1797490/3be40d98b8c56150.png)
ext{
destFile = file('test.xml')
}
task writeTask{
...................
//为Task指定输出
outputs.file = this.destFile
}
task readTask{
//为Task指定输入
inputs.file = this.destFile
.....................
}
readTask的输入为writeTask的输出,所以readTask在writeTask之后执行。
task taskB {
mustRunAfter taskA //在taskA 之后执行
doLast {
println 'taskB'
}
}
4.Settings类
Settings实例与settings.gradle文件一一对应,Settings的实例就是通过settings.gradle文件来实例化的。它用来进行一些项目设置的配置,主要用来指定该工程加载那些Project。该文件在初始化阶段被执行,对于多项目构建必须保证在根目录下有settings.gradle文件,对于单项目构建设置文件是可选的,不过建议还是写上。
5.sourceSets类
SourceSets被称作原集合,一般用它来指定资源的路径。默认的java文件夹下存在我们的源代码文件,res文件夹下存在我们的资源文件。我们可以通过SourceSets类提供的方法来修改。
sourceSets {
main {
jniLibs.srcDirs = ['libs'] //修改so库存放位置
//指定资源文件夹,让资源文件也分模块
res.srcDirs = ['src/main/res',
'src/main/res-ad',
'src/main/res-player']
}
}
总结
Gradle 的核心是基于 Groovy 的 领域特定语言 (DSL), 具有十分优秀的扩展性. Gradle 通过提供可以随意集成的声明式语言元素将声明性构建推到了一个新的高度。它可以被充分利用在你的构建中,它具有强大的灵活性, 可以满足使用者对 Gradle 的一些特别的需求。它不仅仅是一个构建工具。我更愿意把他理解为一个编程框架。
网友评论