Android Gradle构建脚本

网友投稿 748 2022-05-30

Gradle构建脚本使用Groovy来编写。默认的构建文件名为build.gradle 。Gradle命令在构建时,会寻找一份名为build.gradle的文件,然后执行。

在android studio项目中,默认情况下,根目录有一份build.gradle ,各个module也各有一份。

在android studio项目里的任意一份build.gradle文件里定义一个hello任务,执行gradle命令时,就会在这些build.gradle文件中寻找所有定义的hello任务,从根目录开始逐个执行,如:

在根目录的build.gradle文件中定义:

task hello { println 'Hello world root' }

1

2

3

在app module目录的build.gradle文件中定义:

task hello { println 'Hello world app' }

1

2

3

在build.gradle所在目录使用gradle命令运行这个task

juk@Juk-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q hello Hello world root Hello world app

1

2

3

也可以直接运行项目,然后在build的日志窗口可以看到输出

Gradle构建脚本中的Project对象

Project对象是实现了org.gradle.api.Project接口的对象。在build.gradle这个脚本中, 我们就会使用Project对象与Gradle构建命令打交道。通过它,我们访问很多Gradle提供的功能特性。

build.gradle文件与Project对象有一个一对一的关系。在构建初始化时,gradle会为每一个参与到构建中来的项目模块(module)组装一个Project对象,具体过程是这样的:

首先,为本次构建,创建org.gradle.api.initialization.Settings实例。执行settings.gradle脚本中的内容,并对Settings对象进行配置。它主要声明一些配置,用于实例化和配置参与构建的Project对象的层次。一个Settings对象对应于一份settings.gradle文件。这一步是在开始构建前完成的。

使用配置好的Settings对象创建Project实例的层次

最后,通过执行各个项目(module)的build.gradle配置各自的Project对象。执行的顺序,默认情况是从父项目(父module)再到子项目(子module)。

build.gradle的组成

一般,一个项目(module)对应一份build.gradle脚本。我们会用build.gradle脚本去配置Project对象。所以 build.gradle的组成就是Project对象的组成。

Tasks

一个Project对象基本上就是Tasks对象的集合。每个task都执行一些基本的工作,如编译类,运行单元测试,压缩WAR包,生成JavaDoc。每个task都属于某一个Project对象。Task对象是由TaskContainer对象负责创建的,在脚本中可以直接使用task的名字直接调用。在构建脚本中使用task关键字就可以声明task了:

Android Gradle构建脚本

task helloTask task helloTask {} task helloTask(type:Delete) task helloTask(type:Delete){} // 创建hello1 task task(hello1) { println "Good morning!1" } // 创建hello2 task task('hello2') { println "Good morning!" } // 创建hello3 task tasks.create(name:'hello3') { println "Good afternoon!" }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

上面这些声明都是合法的

一个task是由一系列的行为对象组成的。当task被执行时,它们就会依次被执行。

给task hello2添加一个依赖

task hello1 { doLast { println 'Hello world 1' } } task hello2(dependsOn: 'hello1') { doLast { println 'Hello world 2' } }

1

2

3

4

5

6

7

8

9

10

11

上面这种方式还可以换成以下这种方式:

task hello2 { doLast { println 'Hello world 2' } } task hello1 { doLast { println 'Hello world 1' } } hello2.dependsOn hello1

1

2

3

4

5

6

7

8

9

10

11

12

13

依赖还可以这样来写:

task hello2 { doLast { println 'Hello world 2' } } task hello1 { doLast { println 'Hello world 1' } } hello2.dependsOn { tasks.findAll { taskIt -> taskIt.name.startsWith('hello1') } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

运行结果都是:

juk@JukLings-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q hello2 Hello world 1 Hello world 2

1

2

3

doLast的意思就是将这个task 行为放到task的行为列表的最后面。

project.ext.skipStage = 'Hello' task skipTask { doLast { println 'Hello world' } } // 当有这个skipStage属性时才执行skipTask,没有时跳过skipTask,因当前面有定义skipStage这个属性,因此会执行skipTask skipTask.onlyIf{ project.hasProperty('skipStage') }

1

2

3

4

5

6

7

8

9

10

11

还可以通过抛异常的方式来跳过,如上面的代码可以换成下面的来实现:

project.ext.skipStage = 'Hello' task skipTask { doLast { println 'Hello world' } } skipTask.doFirst { if(!project.hasProperty('skipStage')){ throw new StopExecutionException() } }

1

2

3

4

5

6

7

8

9

10

11

12

结果都是:

juk@JukLings-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q skipTask Hello world

1

2

3

在它要执行task之前,Gradle会经历不同的阶段。首先是配置阶段,过后就是执行阶段,这个阶段它就会执行task的doFirst或doLast闭包里的代码。

这里要给大家说明一下, 下面这种task的写法是OK的:

task hello { println 'Hello world 1' } hello { println 'Hello world 2' }

1

2

3

4

5

6

7

结果:

juk@JukLings-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q hello Hello world 1 Hello world 2

1

2

3

4

Dependencies

依赖配置应该是大家最熟悉的了。最常见就是下面这些:

dependencies { // 只能在当前项目(module)使用 implementation 'group:name:version' // 共享 api 'group:name:version' // 单元测试 testImplementation 'group:name:version' // android测试 androidTestImplementation 'group:name:version' ... }

1

2

3

4

5

6

7

8

9

10

11

在脚本就是这样配置的,它在Project对象中是由DependencyHandler对象管着的。

Repositories

指定外部依赖的源,就是告诉gradle去这个仓库下载我们添加的依赖。

repositories { google() mavenCentral() }

1

2

3

4

指定自己的依赖仓库,也是用这个

repositories { maven { url "http://repo.juk.com/maven2" } }

1

2

3

4

5

在脚本中配置的这些会用来配置在Project对象中的RepositoryHandler对象管着的。

如果你要上传你压缩包到maven仓库,那么你可以在maven插件的uploadArchives task用repositories指定上传位置

apply plugin: 'maven' // 要先把maven插件加进来,否则没有uploadArchives任务 uploadArchives { repositories { mavenDeployer { repository(url: "http://repo.juk.com/maven2") } } }

1

2

3

4

5

6

7

8

Plugins

其实插件并没有什么特殊之处,它就是一些task的集合,例如有些插件里有编译的task,设置源文件的task设置等等。添加插件到项目中来其实就是为了扩充Project对象的能力,让它能做更多事。android项目的build.gradle就会有如下的插件:

plugins { id 'com.android.application' id 'kotlin-android' }

1

2

3

4

一般来说插件有两种类型:

一种是脚本插件,它是一构建脚本,会用于构建过程中。

另一种是二进制插件,它们是一些实现了插件接口的类,通过程序的方法来控制构建。

对应的,添加插件也有两种方式:

从本地文件系统添加一份脚本

apply from: 'other.gradle'

1

添加二进制插件

plugins { id 'com.android.application' }

1

2

3

apply plugin: 'com.android.application'

1

首先在build.gradle的开头引用我们的插件

apply plugin: HelloPlugin

1

然后在build.gradle找一个地方定义我们的插件,如文件末尾:

class HelloPlugin implements Plugin { @Override void apply(Project project) { project.task("myHelloTask") { doLast { println 'Hello,My first plugin!' } } } }

1

2

3

4

5

6

7

8

9

10

11

12

如你所见,自定义的插件,需要实现Plugin接口,apply方法的参数,就是当前build.gradle脚本对应的Project对象,从我们定义里可以看出我们往Project对象里添加了一个task,名为myHelloTask,我们也可以通过传进来的project对象去访问它的东西,如定义的属性。 我们来运行一下这个task:

juk@JukLings-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q myHelloTask Hello,My first plugin!

1

2

如何从build.gradle中获得输入?我们可以扩展Project对象,然后通过扩展后的对象来实现,具体如下:

apply plugin: HelloPlugin ... // step 2:使用插件扩展出来的属性对象设置它的属性值 myParameter.message = 'Halo Wo' class HelloPlugin implements Plugin { @Override void apply(Project project) { // step 1:在Project对象中扩展一个属性 myParameter,类型是我们定义的HelloPluginExtension project.extensions.create('myParameter',HelloPluginExtension) project.task("myHelloTask") { doLast { // step 3: 获取build.gradle输入的值 println project.myParameter.message } } } } class HelloPluginExtension { def String message = 'hello plugin' }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

运行任务myHelloTask:

juk@JukLings-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q myHelloTask Halo Wo

1

2

3

注意:在Gradle的版本中已有很多标准插件,如编程语言插件:java ,scala,assembler, c,cpp

例如要引用CPP插件:

apply plugin: cpp

1

查看构建信息

查看Project对象的层次结构

juk@JukLings-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q projects ------------------------------------------------------------ Root project 'HelloWorld' ------------------------------------------------------------ Root project 'HelloWorld' +--- Project ':app' \--- Project ':houseware' To see a list of the tasks of a project, run gradle :tasks For example, try running gradle :app:tasks

1

2

3

4

5

6

7

8

9

10

11

12

13

查看任务

juk@JukLings-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q tasks ------------------------------------------------------------ Tasks runnable from root project 'HelloWorld' ------------------------------------------------------------ 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. buildKotlinToolingMetadata - Build metadata json file containing information about the used Kotlin tooling buildNeeded - Assembles and tests this project and all projects it depends on. bundle - Assemble bundles for all the variants. clean - Deletes the build directory. ......

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

当然你也可以指定看某个项目的task,如houseware项目的task

juklinglee@JukLings-MacBook-Pro HelloWorld % /Users/juklinglee/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q :houseware:tasks ------------------------------------------------------------ Tasks runnable from project ':houseware' ------------------------------------------------------------ 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. ......

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

查看所有属性值

juk@JukLings-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q properties ------------------------------------------------------------ Root project 'HelloWorld' ------------------------------------------------------------ AGP_INTERNAL__MIN_PLUGIN_VERSION_CHECK_STARTED: true _internalAndroidGradlePluginDependencyCheckerRegistered: true allprojects: [root project 'HelloWorld', project ':app', project ':houseware'] android.enableJetifier: true android.useAndroidX: true ant: org.gradle.api.internal.project.DefaultAntBuilder@62b07301 antBuilderFactory: org.gradle.api.internal.project.DefaultAntBuilderFactory@3dbfb745 artifacts: org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated@4bbf11cf asDynamicObject: DynamicObject for root project 'HelloWorld' baseClassLoaderScope: org.gradle.api.internal.initialization.DefaultClassLoaderScope@187dbbc2 buildDir: /Users/juklinglee/AndroidStudioProjects/HelloWorld/build buildFile: /Users/juklinglee/AndroidStudioProjects/HelloWorld/build.gradle ......

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

查看编译环境

juk@JukLings-MacBook-Pro HelloWorld % /Users/juk/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle -q buildEnvironment ------------------------------------------------------------ Root project 'HelloWorld' ------------------------------------------------------------ classpath +--- com.android.tools.build:gradle:7.1.2 | +--- com.android.tools:sdk-common:30.1.2 | | +--- com.android.tools:sdklib:30.1.2 | | | +--- com.android.tools.layoutlib:layoutlib-api:30.1.2 | | | | +--- com.android.tools:common:30.1.2 | | | | | +--- com.android.tools:annotations:30.1.2 | | | | | +--- com.google.guava:guava:30.1-jre | | | | | | +--- com.google.guava:failureaccess:1.0.1 | | |

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

查看某个task的详细使用信息,如查看build 任务:

juklinglee@JukLings-MacBook-Pro HelloWorld % /Users/juklinglee/.gradle/wrapper/dists/gradle-7.2-bin/2dnblmf4td7x66yl1d74lt32g/gradle-7.2/bin/gradle help --task build > Configure project :app C/C++: Could not execute cmake at ...... > Task :help Detailed task information for build Paths :app:build :houseware:build Type Task (org.gradle.api.Task) Description Assembles and tests this project. Group build

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

现在,通过查询我们知道build任务就是用来构建项目的。

最后,以上内容只是gradle的冰山一角,但是看它的源码,你将能很好的理解它是怎么工作的。

Gradle Github地址

Android Gradle

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Executors 封装的四种线程池 各自有何特点,如何使用 超详细 代码动图演示
下一篇:【读书会第十二期】动画图解核心内存区--堆
相关文章