Gradle系列(二) Gradle执行顺序和task

0. 前情提示

Gradle系列已完成,专注于Gradle,有如下几篇文章

1. 什么是gradle

维基百科:Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言来声明项目设置,而不是传统的XML。当前其支持的语言限于Java、Groovy和Scala,计划未来将支持更多的语言。

按我的理解,通俗一点讲,就是拿来构建项目的,我们平时在Android Studio上开发Android项目就是用Gradle进行构建的,相比于传统的xml方式,我感觉更加灵活.毕竟,可以写代码,根据不同的环境搞些骚操作.

gradle里面其实需要学习的有3个

刚哥说过,遇到不会的直接查官方文档,不要每次去搜索引擎东搜西搜,这样效率很低.

这里插播一个小知识点,如何查询官方文档.比如在gradle中经常用的buildscript到底是什么?来到官方文档首页,点开顶部INDEX,搜索buildscript,即可找到这个东西是解释.

2. gradle项目结构

首先我们来新建一个Android项目,什么都不要动.

QZLQBT.png
  • 最外层setting.gradle为根项目的配置,可以知道需要包含哪些模块,然后最外层的build.gralde也是根项目的配置.模块中的build.gradle是子项目的配置.
  • gradle文件夹下面是版本配置以及gradle所需要的脚本
  • 最外层的gradlew为linux/mac下的脚本,gradlew.bat是windows下面用的脚本

3. gradle配置顺序

简单在gradle中输出语句,看看配置顺序

//settings.gradle
println("setting 开始配置")
include ':app'
rootProject.name='Hello'
println("setting 配置完成")
//project build.gradle
println("根build.gradle 开始配置")
buildscript {
    repositories {
    }
    dependencies {
    }
}
println("根build.gradle 配置完成")
//app build.gradle
println("app build.gradle 开始配置")

project.afterEvaluate {
    println "所有模块都已配置完成"
}

android {
    defaultConfig {
    }
    buildTypes {
    }
}

dependencies {
}
println("app build.gradle 配置完成")

打印语句写好后,clean Project,即可执行,输出如下:

setting 开始配置
setting 配置完成

> Configure project :
根build.gradle 开始配置
根build.gradle 配置完成

> Configure project :app
app build.gradle 开始配置
app build.gradle 配置完成
所有模块都已配置完成

可以看到首先是配置setting,知道有哪些模块.然后是配置根项目的build.gradle,然后才是子项目的build.gradle配置.

我在上面加了一个监听器project.afterEvaluate,可以通过查询官方文档了解它的详细内容,这是一个当所有的模块都配置完了的时候的回调.

其中,还可以在settings.gradle中添加一个监听器

gradle.addBuildListener(new BuildListener() {
    @Override
    void buildStarted(Gradle gradle) {
        println("buildStarted------------")
    }

    @Override
    void settingsEvaluated(Settings settings) {
        println("settingsEvaluated------------")
    }

    @Override
    void projectsLoaded(Gradle gradle) {
        println("projectsLoaded------------")
    }

    @Override
    void projectsEvaluated(Gradle gradle) {
        println("projectsEvaluated------------")
    }

    @Override
    void buildFinished(BuildResult result) {
        println("buildFinished------------")
    }
})

在执行构建的时候,这个监听器会监听到主要的生命周期事件,看名字大概就能大概猜出是什么意思,buildStarted已过时.也可以看看官方文档详细了解

加入之后打印如下:

setting 开始配置
setting 配置完成
settingsEvaluated------------
projectsLoaded------------

> Configure project :
根build.gradle 开始配置
根build.gradle 配置完成

> Configure project :app
app build.gradle 开始配置
app build.gradle 配置完成
所有模块都已配置完成
projectsEvaluated------------

buildFinished------------

4. gradle task

4.1 初识task

gradle中所有的构建工作都是由task完成的,它帮我们处理了很多工作,比如编译,打包,发布等都是task.我们可以在项目的根目录下,打开命令行(AS自带,底部有Terminal,打开就行)执行gradlew tasks查看当前项目所有的task.

在命令行如果执行失败,则将项目的JDK location设置成本地jdk的路径,而且jdk的版本还需要是java 8. 我用的jdk版本是1.8.0_231.

> Task :tasks

------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------

Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.
signingReport - Displays the signing info for the base and test modules
sourceSets - Prints out all the source sets defined in this project.

Build tasks
-----------
assemble - Assemble main outputs for all the variants.
assembleAndroidTest - Assembles all the Test applications.
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.
bundle - Assemble bundles for all the variants.
clean - Deletes the build directory.
cleanBuildCache - Deletes the build cache directory.
compileDebugAndroidTestSources
compileDebugSources
compileDebugUnitTestSources
compileReleaseSources
compileReleaseUnitTestSources

Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.

Cleanup tasks
-------------
lintFix - Runs lint on all variants and applies any safe suggestions to the source code.

Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'Hello'.
components - Displays the components produced by root project 'Hello'. [incubating]
dependencies - Displays all dependencies declared in root project 'Hello'.
dependencyInsight - Displays the insight into a specific dependency in root project 'Hello'.
dependentComponents - Displays the dependent components of components in root project 'Hello'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'Hello'. [incubating]
projects - Displays the sub-projects of root project 'Hello'.
properties - Displays the properties of root project 'Hello'.
tasks - Displays the tasks runnable from root project 'Hello' (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.
lintVitalRelease - Runs lint on just the fatal issues in 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

可以看到,这里有很多的task.比如我们在命令行执行gradlew clean就是clean.执行gradlew installDebug就是构建debug项目然后安装到手机上.

4.2 编写task

书写task非常简单,比如我们在根目录的build.gradle中加入一个hello的task

task hello() {
    println "hello world"

    //将给定的闭包 添加到此task操作链表的开头
    doFirst {
        println "hello task doFirst"
    }

    doLast {
        println "hello task doLast"
    }
}

然后在命令行执行gradlew hello,输出如下

setting 开始配置
setting 配置完成

> Configure project :
根build.gradle 开始配置
hello world
根build.gradle 配置完成

> Configure project :app
app build.gradle 开始配置
app build.gradle 配置完成

> Task :hello
hello task doFirst
hello task doLast

它会先配置完成,才会执行.在一个task内部其实拥有一个action列表,执行的时候其实就是执行这个列表,它的类型是一个List.上面的doFirst和doLast就是创建action的两个方法,文档.doFirst是在最开始执行,doLast是在最后执行,大括号里面传入的是闭包.

4.3 task执行顺序

task是有执行顺序的,在创建完Android项目之后,根目录下的build.gradle中,有一个clean的task.这个是AS自动给我们生成的.

task clean(type: Delete) {
    delete rootProject.buildDir
}

我们先在根目录下创建test.txt文件,然后我们在这个task中做一些改动,执行到clean这个task时删除根目录下的test.txt文件.

task clean(type: Delete) {
    delete rootProject.buildDir

    doLast {
        def file = new File('test.txt')
        delete file
        println "清理"
    }
}

然后我们在hello这个task的下面写上

hello.dependsOn clean

这样就表示hello这个task依赖clean这个task,当执行hello这个task时需要先执行clean.
我们在命令行执行gradlew hello看看是不是这样.我执行之后它的输出是

> Task :clean
清理

> Task :hello
hello task doFirst
hello task doLast

先执行clean,再执行hello这个task.而且还看到test.txt文件被删除(如果看到没删除,刷新一下看看)了,那么说明确实是clean先执行.

这个顺序有什么用?其实是很有用的,比如执行安装task的时候,肯定会先执行编译,打包这些步骤.

4.4 自带 gradle task

当我们在AS中创建Android项目的时候,默认会带一些Android的一些gradle task,这些task都是gradle和Android Gradle Plugin给我们创建好的,可以直接用.

Qe1fy9.png

比如我们上面使用到的gradlew clean是用来清理项目的.和编译相关的task主要有:build和assemble,其中build依赖assemble,也就是说执行build之前会先执行assemble。在Android上,会根据buildType和productFlavor的不同自动创建多个assembleXxx任务,如assembleDebug,assembleRelease等,assemble会依赖所有的assembleXxx任务,也就是说执行assemble会先执行assembleDebug,assembleRelease等一系列的assemble任务。

如果想看Android Gradle Plugin源码,可以在app/build.gradle中的dependencies下面引入

compileOnly 'com.android.tools.build:gradle:3.5.2'

然后就可以在项目的External Libraries中看到该jar的源码,

QeUB5R.png

比如clean这个task是在com.android.build.gradle.tasks.CleanBuildCache.java里面定义的

@TaskAction
public void clean() throws IOException {
    Preconditions.checkNotNull(buildCache, "buildCache must not be null");
    buildCache.delete();
}

通过查询gradle官方文档可知,@TaskAction的作用:Marks a method as the action to run when the task is executed. 将方法标记为执行任务时要运行的动作.

5.Build script blocks

还有一个东西,就是几乎每个项目都需要用到的地方,但是我之前却根本不知道它真正的名字.就是Build script blocks,打开项目的根目录的build.gradle文件.

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.2'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

每个项目都需要配置这些东西,但是我们真的知道他们的含义么?

首先是buildscript,查询文档可知:

void buildscript​(Closure configureClosure)

Configures the build script classpath for this project.

The given closure is executed against this project's ScriptHandler. The ScriptHandler is passed to the closure as the closure's delegate.

为该项目配置构建脚本类路径.参数是Closure,闭包.这个闭包是委托给了ScriptHandler,又去看看ScriptHandler

dependencies​(Closure configureClosure)  Configures the dependencies for the script.
repositories​(Closure configureClosure)   Configures the repositories for the script dependencies.

dependencies​是添加编译依赖项的,repositories​是为脚本依赖项配置存储库.他们的配置,都是用闭包的形式.

然后dependencies​又是委托了DependencyHandler进行配置,对于怎么配置,官方还给了示例

Example shows a basic way of declaring dependencies.

 apply plugin: 'java'
 //so that we can use 'implementation', 'testImplementation' for dependencies

 dependencies {
   //for dependencies found in artifact repositories you can use
   //the group:name:version notation
   implementation 'commons-lang:commons-lang:2.6'
   testImplementation 'org.mockito:mockito:1.9.0-rc1'

   //map-style notation:
   implementation group: 'com.google.code.guice', name: 'guice', version: '1.0'

   //declaring arbitrary files as dependencies
   implementation files('hibernate.jar', 'libs/spring.jar')

   //putting all jars from 'libs' onto compile classpath
   implementation fileTree('libs')
 }

6. 总结

本文带大家梳理了Gradle的执行顺序,Task和Build script blocks这些知识点.为了更好的认识Gradle.现在对Gradle了解又深了一步,而且如果以后遇到不懂的还知道到哪里去查文档,方便快捷,不用再到处搜了.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容