Gradle脚本基础全攻略

本文发布时间: 2019-Mar-22
【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流】1 背景在开始Gradle之前请务必保证自己已经初步了解了Groovy脚本,特别是闭包规则,如果还不了解Groovy则可以先看《Groovy脚本基础全攻略》这一篇博客速成一下Groovy基础,然后再看此文即可。关于Gradle速成干货基础详情也请参考Geadle官方网站,不好意思我太Low了。Gradle核心是基于Groovy的领域特定语言(DSL,具体概念参见《Groovy脚本基础全攻略》),具有非常好的扩展性,所以不管是简单的独立项目还是大型的多项目构建它都能高效的提高构建任务,尤其对多项目支持是非常牛逼的;Gradle还提供了局部构建功能,譬如构建一个单独子项目时它会构建这个子项目依赖的所有子项目;当然了他对远程仓库和本地库的支持也很到位;哎呀,总之后面你就明白他的牛逼之处了。既然Gradle核心是Groovy,Groovy本质又是Java,所以很明显可以发现Gradle环境必须依赖JDK与Groovy库,具体如下:JDK版本必须是JDK6以上;因为Gradle自带Groovy库, 所以已安装的Groovy会被Gradle忽略;具体Gradle环境配置好了以后如下图:【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流】2 Gradle DSL基础Gradle的实质是配置脚本,执行一种类型的配置脚本时就会创建一个关联的对象,譬如执行Build script脚本就会创建一个Project对象,这个对象其实就是Gradle的代理对象。下面给出来各种类型Gradle对应的对象类型:脚本类型关联对象类型Build scriptProjectInit scriptGradleSettings scriptSettingsGradle的三种主要对象解释如下:Project对象:每个build.gradle会转换成一个Project对象。Gradle对象:构建初始化时创建,整个构建执行过程中只有这么一个对象,一般很少去修改这个默认配置脚本。Settings对象:每个settings.gradle会转换成一个Settings对象。可以看见,当我们编写指定类型Gradle脚本时我们可以直接使用关联对象的属性和方法;当然了,每个脚本也都实现了Script接口,也就是说我们也可以直接使用Script接口的属性与方法。2-1 构建脚本Build script(Project)在Gradle中每个待编译的工程都是一个Project(每个工程的build.gradle对应一个Project对象),每个Project在构建的时候都包含一系列Task,这些Task中很多又是Gradle的插件默认支持的。PS:所谓的我们编写Gradle脚本,实质大多数时候都是在编写构建脚本Build script,所以说Project和Script对象的属性和方法等API非常重要。每一个Project对象和build.gradle一一对应,一个项目在构建时都具备如下流程:为当前项目创建一个Settings类型的实例。如果当前项目存在settings.gradle文件,则通过该文件配置刚才创建的Settings实例。通过Settings实例的配置创建项目层级结构的Project对象实例。最后通过上面创建的项目层级结构Project对象实例去执行每个Project对应的build.gradle脚本。2-2 初始化脚本Init script(Gradle)和设置脚本Settings script(Settings)Gradle对象:初始化脚本Init script(Gradle)类似于Gradle的其他类型脚本,这种脚本在构建开始之前运行,主要的用途是为接下来的Build script做一些准备工作。我们如果需要编写初始化脚本Init script,则可以把它按规则放置在USER_HOME/.gradle/相关目录下。譬如:初始化脚本的Gradle对象代表了Gradle的调运,我们可以通过调用Project对象的getGradle()方法获得Gradle实例对象。Settings对象:在对工程进行配置(譬如多项目树构建)时Settings实例与settings.gradle文件一一对应,它用来进行一些项目设置的配置。这个文件一般放置在工程的根目录。譬如:2-3 Build生命周期Gradle的构建脚本生命周期具备三大步,如下:可以看见,生命周期其实和上面构建脚本Build script的执行流程是可以关联上的。有了这个流程图我们接下里详细看下每个过程。settings.gradle文件:除了构建脚本文件,Gradle还定义了一个约定名称的设置文件(默认为settings.gradle)。该文件在初始化阶段被执行,对于多项目构建必须保证在根目录下有settings.gradle文件,对于单项目构建设置文件是可选的,不过建议还是写上。如下是单项目构建的一个例子://settings.gradleprintln 'This is executed during the initialization phase.'//build.gradleprintln 'This is executed during the configuration phase.'task configured { println 'This is also executed during the configuration phase.'}task test << { println 'This is executed during the execution phase.'}task testBoth { doFirst { println 'This is executed first during the execution phase.' } doLast { println 'This is executed last during the execution phase.' } println 'This is executed during the configuration phase as well.'}运行构建结果:> gradle test testBothThis is executed during the initialization phase.This is executed during the configuration phase.This is also executed during the configuration phase.This is executed during the configuration phase as well.:testThis is executed during the execution phase.:testBothThis is executed first during the execution phase.This is executed last during the execution phase.BUILD SUCCESSFULTotal time: 1 secsGradle多项目构建:多项目构建总是需要指定一个树根,树中的每一个节点代表一个项目,每一个Project对象都指定有一个表示在树中位置的路径;在设置文件中我们还可以使用一套方法来自定义构建项目树。//分层布局的多项目构建settings.gradle文件include 'project1', 'project2:child', 'project3:child1'上面例子中把project的路径作为了include方法的参数,譬如上面的’project3:child1’参数就指定了物理路径的project3/child1(project3/child1是相对于多项目根路径的相对路径),这也同时意味着会创建’project3’和’project3:child1’两个project。//平面布局的多项目构建settings.gradle文件includeFlat 'project3', 'project4'上面例子中includeFlat方法接受目录名作为参数,但是特别注意,这些项目目录必须是根目录的兄弟目录。当然了,设置文件中创建的多项目树其实是由项目描述符来描述的,我们可以在设置文件中随时修改这些描述符。如下://settings.gradlerootProject.name = 'main'project(':projectA').projectDir = new File(settingsDir, '../my-project-a')project(':projectA').buildFileName = 'projectA.gradle'可以看见,如上例子通过描述符更改名称和项目目录,并且建立了一个项目的文件。Gradle构建初始化Initialization:在初始化阶段如果我们在根路径下直接指明settings.gradle文件和相关配置则构建初始化就会直接按照我们的设置去构建项目,如果我们没指明settings.gradle文件则Gradle会以一定的规则去寻找settings.gradle文件,然后依据寻找结果的不同去决定如何构建项目。【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流】3 Gradle构建基础通过上一章可以知道,每一个Gradle构建都是由一个或多个project构成,每一个project都是由一个或多个tasks构成,每个task的实质其实是一些更加细化的构建(譬如编译class、创建jar文件等)。任务task基础:如下例子我们先来直观感受一下task的概念,具体细节后面会探讨://创建一个名为build.gradle的文件task hello { doLast { println 'Hello world!' }}//这是快捷写法,用<<替换doLast,后面解释task hl << { println 'Hello world!'}//创建upper的task,使用Groovy语言编写task upper << { String someString = 'mY_nAmE' println 'Original: ' + someString println 'Upper case: ' + someString.toUpperCase()}通过如下命令运行构建上面名为hello的task,具体如下:[email protected]:~/$ gradle hello:helloHello world!BUILD SUCCESSFULTotal time: 1.037 secs可以看见,gradle命令会在当前目录中查找一个叫build.gradle的构建脚本文件,这个构建脚本定义了一个叫做hello的独立task,并且添加了一个action,我们执行了这个task就得到了想要的结果。在这里再多嘴一句,我们看下task有无action的区别,如下://有Action的tasktask actionTask << { println 'I am actionTask' } //无Action的tasktask noActionTask { println 'I am noActionTask' } 一定要记住,在上面这个例子中如果task没有加<<则这个任务在脚本初始化initialization阶段(即无论执行啥task都被执行,具体参见上一章的第一个例子)被执行,如果加了<<则在gradle actionTask后才执行。因为没有加<<则闭包在task函数返回前会执行,而加了<<则变成调用actionTask.doLast(),所以会等到gradle actionTask时执行。任务task依赖:我们通过上面task基础感受的例子可以发现,一个build.gradle文件中定义多个task互相没有关系,决定执行的是我们gradle命令后面跟的task名字;那我们要是让他们之间有依赖关系咋办呢?如下:task taskX(dependsOn: 'taskY') << { println 'taskX'}task taskY << { println 'taskY'}运行结果如下:[email protected]:~/$ gradle taskX:taskYtaskY:taskXtaskXBUILD SUCCESSFULTotal time: 1.039 secs动态任务task:我们还可以在Gradle中使用Groovy来创建动态task,如下:4.times { counter -> task 'task$counter' << { println 'I'm task number $counter' }}运行结果如下:[email protected]:~/$ gradle task1:task1I'm task number 1BUILD SUCCESSFULTotal time: 1.397 secs使用已存在任务task:我们除过在上面定义任务task时指明依赖以外还可以通过API为任务加入一个依赖,如下:4.times { counter -> task 'task$counter' << { println 'I'm task number $counter' }}task0.dependsOn task2, task3运行结果如下:[email protected]:~/$ gradle task0:task0I'm task number 2I'm task number 3I'm task number 0BUILD SUCCESSFULTotal time: 1.397 secs或者我们还可以通过API为任务加入一些新行为,如下:task hello << { println 'Hello Earth'}hello.doFirst { println 'Hello Venus'}hello.doLast { println 'Hello Mars'}hello << { println 'Hello Jupiter'}运行结果如下:[email protected]:~/$ gradle hello:helloHello VenusHello EarthHello MarsHello JupiterBUILD SUCCESSFULTotal time: 1.397 secs可以发现,doFirst和doLast可以被执行多次,<<操作符实质就是doLast。任务task短标记:我们可以通过美元符将一个task作为另一个task的属性,如下:task hello << { println 'Hello world!'}hello.doLast { println 'Greetings from the $hello.name task.'}执行结果如下:[email protected]:~/$ gradle hello:helloHello world!Greetings from the hello task.BUILD SUCCESSFULTotal time: 1.397 secs可以看见,上面脚本中使用的name其实是任务的默认属性, 代表当前任务的名称。自定义任务task属性:我们还可以给任务task加入自定义的属性,如下例子:task myTask { ext.myProperty = 'myValue'}task printTaskProperties << { println myTask.myProperty}执行结果如下:[email protected]:~/$ gradle printTaskProperties:printTaskPropertiesmyValueBUILD SUCCESSFULTotal time: 1.397 secs定义默认任务task:Gradle允许在脚本中定义一个或多个默认任务,如下:defaultTasks 'clean', 'run'task clean << { println 'Default Cleaning!'}task run << { println 'Default Running!'}task other << { println 'I'm not a default task!'}执行结果如下:[email protected]:~/$ gradle:clean,runDefault Cleaning!Default Running!BUILD SUCCESSFULTotal time: 1.397 secs【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流】4 Gradle依赖管理基础大多数项目都不是完全独立的,它们需要依赖其他项目进行编译等,Gradle允许你告诉它你项目的依赖关系,以便找到这些依赖关系,并在你的构建中维护这些依赖关系,依赖关系可能需要从远程的Maven等仓库中下载,也可能是在本地文件系统中,或者是通过多项目构建另一个构建,我们称这个过程为依赖解析。Gradle依赖声明:关于依赖声明不解释,直接给个例子,如下:apply plugin: 'java'repositories { mavenCentral()}dependencies { compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final' testCompile group: 'junit', name: 'junit', version: '4.+'}Gradle依赖配置:在Gradle中依赖可以组合成configurations(配置),一个配置简单地说就是一系列的依赖,通俗说也就是依赖配置;我们可以使用它们声明项目的外部依赖,也可以被用来声明项目的发布。下面我们给出几种Java插件中常见的配置,如下:compile用来编译项目源代码的依赖;runtime在运行时被生成的类需要的依赖,默认项,包含编译时的依赖;testCompile编译测试代码依赖,默认项,包含生成的类运行所需的依赖和编译源代码的依赖;testRuntime运行测试所需要的依赖,默认项,包含上面三个依赖;各种各样的插件支持许多标准的配置,我们还可以定义自己的配置。Gradle外部依赖:我们可以用Gradle声明许多种依赖,其中有一种是外部依赖(external dependency),它是在当前构建之外的一种依赖,一般存放在远程(譬如Maven)或本地的仓库里。如下是一个外部依赖的例子:dependencies { compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'}可以看见,引用一个外部依赖需要用到group、name、version属性。上面的写法还有一种简写,如下规则:group:name:version这是一个简写的例子:dependencies { compile 'org.hibernate:hibernate-core:3.6.7.Final'}Gradle仓库:有了上面的外部依赖,你指定会想Gradle是咋找到那些外部依赖文件的。其实Gradle会在一个仓库(repository)里找这些依赖文件,仓库其实就是很多依赖文件的集合服务器, 他们通过group、name、version进行归类存储,好在Gradle可以解析好几种不同的仓库形式(譬如Maven等),但是Gradle默认不提前定义任何仓库,我们必须手动在使用外部依赖之前定义自己的仓库。下面是一个使用MavenCentral仓库的例子:repositories { mavenCentral()}这是一个使用远程Maven仓库的例子:repositories { maven { url 'http://repo.mycompany.com/maven2' }}这是一个使用本地文件系统里库的例子:repositories { ivy { // URL can refer to a local directory url '../local-repo' }}当然了,一个项目可以有好几个库,Gradle会根据依赖定义的顺序在各个库里寻找它们,在第一个库里找到了就不会再在第二个库里找它了,否则在第二个库找。Gradle发布artifacts:依赖配置也可以用来发布文件,我们可以通过在uploadArchives任务里加入仓库来完成。下面是一个发布到Maven 库的例子,Gradle将生成和上传pom.xml,如下:apply plugin: 'maven'uploadArchives { repositories { mavenDeployer { reposito


(以上内容不代表本站观点。)
---------------------------------
本网站以及域名有仲裁协议。
本網站以及域名有仲裁協議。

2020-Jul-13 01:12am
栏目列表