环境配置
- 官方地址:https://gradle.org/releases/
-
下载之后将gradle下面的bin目录添加到系统的Path中(Android studio目录一般都是在.gradle目录下)
- 测试是否配置好:gradle -v
Hello Gradle
- 新建一个build.gradle
println("Hello Gradle")
- cmd定位到新建文件目录下
gradle help
-
查看输出结果
- build.gradle是构建Project的核心文件,也是入口:
- 如果没有该文件,会出现not found in root project 'xxxxx' 提示异常。
- 必须要有一个可以运行的task,运行后自动生成.gradle文件夹下的内容
gradle wrapper
- Gradle Wrapper用来配置开发过程中用到的Gradle构建工具版本。避免因为Gradle不统一带来的不必要的问题
- 在工程目录下使用cmd命令生成wrapper:
gradle wrapper
- 标准的gradle工程目录
- gradlew和gradlew.bat分别是Linux和Windows下的可执行脚本
- 具体业务逻辑是在/gradle/wrapper/gradle-wrapper.jar中实现
-
gradlew最终还是使用Java执行这个jar包来执行相关的Gradle操作
gradle-wrapper.properties
- distributionBase:下载的Gradle压缩包解压后存储的主目录
- distributionPath:相对于distributionBase的解压后的Gradle压缩包的路径
- distributionUrl:Gradle发行版压缩包的下载地址
- bin:二进制发布版。
- all:bin基础上还包含了源码和文档。
- zipStoreBase:同distributionBase,只不过存放的是zip压缩包的
- zipStorePath:同distributionPath,只不过存放的是zip压缩包的
gradle构建机制
android gradle工程目录
Gradle DSL
- DSL(Domain Specific Language) 领域特定语言,或领域专属语言。简单来说就是专门关注某一领域的语言,它在于专而不是全,最典型的比如HTML。
- Gradle可以使用Groovy DSL,专门用来开发Gradle的构建脚本。所以说Gradle整体设计是以作为一种语言为导向的,并非成为一个严格死板的框架
settings.gradle
- Gradle支持多工程构建,使用settings.gradle来配置添加子工程(模块)。
- settings文件在初始化阶段执行,创建Settings对象,在执行脚本时调用该对象的方法。
- Settings.include(String... projectPaths):
- 将给定的目录添加到项目构建中,':app'表示文件相对路径,相当于'./app'文件夹。
- 多项目架构进行分层,把同层次的子工程放在同一文件夹下便于管理,使用':xxx:yyy'表示
build.gradle
- build.gradle是项目构建文件,每个工程都有一个build.gradle文件。
- build.gradle在配置阶段执行,并创建相应工程的Project对象,执行的代码可以直接调用该对象提供的方法或属性
Daemon(守护进程)
- 项目启动时,会开启一个client,然后启动一个daemon,通过client向daemon收发请求,项目关闭,client关闭,daemon保持启动,有类似项目再次部署时,会直接通过新的client访问已经启动的daemon,所以速度很快,默认daemon不使用3小时后关闭;不同项目兼容性考虑,也可使用--no-daemon 启动项目,就没有速度优势了
- 手动停止daemon:gradle wrapper --stop
生命周期
- Initialization
- Gradle支持单项目和多项目构建。在初始化阶段,Gradle确定哪些项目参与构建,并为每个项目创建project实例,比如解析setting.gradle
- Configuration
- 配置阶段,解析每个工程的build.gradle文件,创建要执行的任务子集和确定各种任务之间的关系,并对任务做一些初始化配置
- 解析过程中并不会执行各个build.gradle中的task
- 经过Configration阶段,Project之间及内部Task之间的关系就确定了
- 一个Project包含很多Task,每个Task之间有依赖关系。Configuration会建立一个有向图来描述Task之间的依赖关系
- 所有Project配置完成后,会有一个回调project.afterEvaluate(),表示所有的模块都已经配置完了
- Execution
- 运行阶段,Gradle根据配置阶段创建和配置要执行的任务子集,执行任务
执行流程
自定义任务
task
- task是gradle中最小的任务单元,任务之间可以进行复杂的操作(如动态创建任务,多任务间依赖调用等等)。gradle的执行其实就是由各种任务组合执行,来对项目进行构建的
- gradlew tasks -all命令查看所有任务
- gradlew A B 命令表示执行任务A和B
自定义任务
- build.gradle中自定义任务
-
task(任务名){}
-
- { }执行的是配置阶段的代码,执行阶段要处理的逻辑需要调用doFirst、doLast方法,在闭包中实现。
- doFirst{}表示任务执行开始时调用的方法
- doLast{}表示任务执行结束调用的方法。
- task A(dependsOn:[B]){} 表示任务A依赖于任务B,那么B执行在A之前。
task A {
println("Hello A")
doLast {
println("doLast A")
}
}
task B {
println("Hello B")
doLast {
println("doLast B")
}
}
task test(dependsOn: [A, B]) {
doLast {
println("doLast test")
}
}
A.dependsOn(B)
- 自定义的任务默认分组到other中。
DefaultTask
- task定义的任务其实就是DefaultTask的一种具体实现类的对象。
- 可以使用自定义类继承DeaflutTask:
- 在方法上使用@TaskAction注解,表示任务运行时调用的方法。
- 使用@Input表示对任务的输入参数。
- 使用@OutputFile表示任务输出文件。
- 使用inputs,outputs直接设置任务输入/输出项。
- 一个任务的输出项可以作为另一个任务的输入项 (隐式依赖关系)。
获取任务的类型
task A {
}
println(A.class)//class org.gradle.api.DefaultTask_Decorated
自定义任务类型实现自定义任务
-
创建一个自定义任务
- 自定义任务实现文件的输入输出
class MyTask extends DefaultTask {
String from
File out
@TaskAction
void method() {
println "我是自定义任务"
//文件进行操作
println inputs.files.singleFile
def inFile = inputs.files.singleFile
//将build.gradle文件复制到test文件
def outFile = outputs.files.singleFile
outFile.createNewFile()
outFile.text = inFile.text
}
}
task myTask(type: MyTask) {
from = "I am Peakmain"
out = file("test.txt")
inputs.file file('build.gradle')
outputs.file file('test.txt')
}
细心的人可能会发现,我们执行多次的时候并没有打印,这是因为我们的内容没有改变,所以会直接跳过@TaskAction方法,如果我们想每次都执行TaskAction怎么解决,我们可以在构造函数中添加一行代码
MyTask() {
outputs.upToDateWhen {
false
}
}
钩子函数
初始化阶段
android中的settings.gradle中主要是gradle的初始化,具体大家看上面Gradle执行流程图
gradle.projectsLoaded {
println "gradle.projectsLoaded"
}
gradle.settingsEvaluated {
println "gradle.settingsEvaluated"
}
Terminal中执行命令:gradlew help,我们便可以看到我们的打印
配置阶段
gradle对项目所有library生效,project只对当前library生效
gradle.beforeProject {
println "gradle.beforeProject"
}
gradle.afterProject {
println "gradle.afterProject"
}
//所有配置完成之后执行
gradle.taskGraph.whenReady {
println "gradle.taskGraph.whenReady"
}
//只对当前有效
project.beforeEvaluate {
//root无效
println "beforeEvaluate"
}
project.afterEvaluate {
println "afterEvaluate"
}
结果
gradle设置监听
//为gradle设置监听
gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
@Override
void beforeEvaluate(Project project) {
println "beforeEvaluate"
}
@Override
void afterEvaluate(Project project, ProjectState projectState) {
println "afterEvaluate"
}
})
//设置构建监听
gradle.addBuildListener(new BuildListener(){
@Override
void buildStarted(Gradle gradle) {
}
@Override
void settingsEvaluated(Settings settings) {
}
@Override
void projectsLoaded(Gradle gradle) {
}
@Override
void projectsEvaluated(Gradle gradle) {
}
@Override
void buildFinished(BuildResult buildResult) {
}
})
Project
- build.gradle在配置阶段会生成project实例,在build.gradle中直接调用方法或属性,实则是调用当前工程的project对象的方法或属性
- 使用Project提供的api,更方便在多项目构建设置
- project(":app"){}指定的project(这里是app)配置
- allprojects{}所有的project配置
- subprojects{}所有的子project 配置
- buildscript{}此项目配置构建脚本类路径
属性扩展
- 使用ext对任意对象属性进行扩展
- 对project进行使用ext进行属性扩展,对所有子project可见
- 一般在root project进行ext属性扩展,为子工程提供复用属性,通过rootProject直接访问
- 任意对象都可以使用ext来添加属性:使用闭包,在闭包定义扩展属性。直接使用=赋值,添加扩展属性
- 由谁进行ext调用,就属于谁的扩展属性
- 在build.gradle中,默认当前工程的project对象,所以在build.gradle直接使用"ext="或者"ext{}"其实就是给project定义扩展属性
- 使用gradle.properties以键值对形式定义属性,所有project可直接使用
ext{//相当于project.ext
author="peakmain"
}
task myTask{
}
myTask.ext.username="peakmain"
println(myTask.ext.username)
println(myTask.username)
Gradle插件
脚本插件
afterEvaluate {
println tasks.getByName("packageDebug")
task zip(type: Zip) {
archiveName "outputs.zip"// 输出的文件名字
destinationDir file("${buildDir}/custom")// 输出的文件存放的文件夹
from tasks.getByName("packageDebug").outputs.files// 输入的文件
tasks.getByName("packageDebug").outputs.files.each {
println it
}
}
}
二进制插件
class MyTask implements Plugin<Project>{
@Override
void apply(Project project) {
println("MyTask")
}
}
apply plugin:MyTask
自定义Gradle插件,实现packageDebug的打包
1.新建buildSrc目录
2.新建一个build.gradle,同步构建一下
3.新建文件夹src/main/java
4.build.gradle引入插件
apply plugin:"java"
5.新建PeakmainPlugin.java类
public class PeakmainPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.afterEvaluate(it -> {
System.out.println(it.getTasks().getByName("packageDebug"));
Map<String, Class<?>> typeMap = new HashMap<>();
typeMap.put("type", Zip.class);
Zip zipTask = (Zip) project.task(typeMap, "zipDebug");
zipTask.setArchiveName("outputs.zip");
zipTask.setDestinationDir(new File(project.getBuildDir().getAbsolutePath() + "/custom"));
zipTask.from(it.getTasks().getByName("packageDebug").getOutputs().getFiles());
});
}
}
6.app目录下的build.gradle引入插件,同步一下
apply plugin:PeakmainPlugin
7.AndroidStudio右边的Gradle的Other多了一个zipDebug
8.结果