当前位置:   article > 正文

Kotlin中的Gradle_build.gradle.kts

build.gradle.kts

Grandle程序

第一个Gradle程序

1.创建

左上角【File】->【New Project】->【Project】,出现以下画面,如下勾选

在配置Gradle时,需要连接网络下载资源,不然会出现配置失败的情况。

若在构建完毕后,左侧的路径中没有出现src包,可以在build.gradle文件中最外部添加如下内容(对应的是5.X版本的Gradle):

  1. task 'create-dirs' {
  2. doLast {
  3. sourceSets*.java.srcDirs*.each {
  4. it.mkdirs()
  5. }
  6. sourceSets*.resources.srcDirs*.each {
  7. it.mkdirs()
  8. }
  9. }
  10. }

点击右侧栏进行如下操作: 

 

2.配置

Gradle是从4.0开始支持Kotlin的,所以一般的Gradle版本要求是要在4.0以上。

默认IDEA使用的是groovy脚本构建的,若想使用Kotlin语言构建,可以将build.gradle文件重命名为build.gradle.kts,为保证修改成功,建议重启IDEA。若build.gradle.kts文件的图标变更,则说明修改成功。

此时将build.gradle.kts文件内容修改为以下内容:

  1. plugins {
  2. application
  3. }
  4. application{
  5. mainClassName="com.example.gradleExample.Main"
  6. }

“mainClassName”中对应的是程序入口类的绝对路径,Main类在后续会创建。

3.创建功能类

首先在src/main/java中创建与绝对路径同名的包名。

在该包下分别创建Girl和Main类。

  1. public class Girl {
  2. public String greeting() {
  3. return "Hello";
  4. }
  5. }
  1. public class Main {
  2. public static void main(String[] args) {
  3. Girl girl = new Girl();
  4. System.out.println(girl.greeting());
  5. }
  6. }

4.运行

打开侧边栏中的Gradle,也可如图中点击选项打开。

 在打开的Gradle Project中,双击run会运行刚才的Main类。

运行结果如图所示。

 在运行之后,在distribution文件夹中可见一个distZip标识。

双击该标识可将该程序发布,路径位于build/distributions中。

解压该文件,会出现两个文件夹,分别是lib和bin,其中lib文件夹中有一个jar文件,是程序中的代码编译成的一个jar包;bin文件夹中有两个文件,分别是同名文件和bat文件。

同名文件是linux环境下运行需要的脚本,bat文件是Windows环境下运行需要的脚本。在cmd中,将bat文件拖入窗口回车,会运行刚才我们编写的程序并输出结果。 

Java代码和Kotlin代码共存 

Gradle之前是使用groovy脚本编写的,是一种基于JVM的动态语言,常见的动态语言有Python和JavaScript,动态语言是动态运行的,在编译时编译器无法识别它需要干什么。

后来出现了Kotlin,Kotlin和Java都是静态语言,在之后Gradle开始使用Kotlin进行编写。

1.配置build.gradle.kts文件

为使程序可以编写java代码又可以编写kotlin代码,可对build.gradle.kts文件做如下修改:

  1. plugins {
  2. application
  3. kotlin("jvm")
  4. }
  5. application {
  6. mainClassName = "com.example.gradleExample.Main"
  7. }
  8. dependencies {
  9. compile(kotlin("stdlib"))
  10. }
  11. repositories {
  12. jcenter()
  13. }

使用application构建工具可以编写java代码,如果想同时编写kotlin代码,需要依赖kotlin-stdlib.jar包,这个包是kotlin的标准库。

repositories用于声明仓库,在示例中从jcenter仓库中下载依赖;

然后在dependencies节点中,通知jcenter仓库需要依赖(compile)kotlin中的stdlib.jar包;

而在application中的mainClassName声明的是程序的入口,即Main.java

配置build.gradle.kts文件后,在src/main文件夹下创建kotlin文件夹并刷新项目,kotlin文件夹颜色变为蓝色后,该项目就可以运行kotlin文件了。

若刷新项目在jvm处报错,则需要指定版本号。

  1. plugins {
  2. application
  3. kotlin("jvm") version "1.3.61"}
  4. application {
  5. mainClassName = "com.example.gradleExample.Main"
  6. }
  7. dependencies {
  8. compile(kotlin("stdlib"))
  9. }
  10. repositories {
  11. jcenter()
  12. }

2.创建Boy.kt

在刚刚创建的kotlin文件夹中,如同刚才在java中,创建一个与绝对路径同名的包,并在该包中创建一个Boy.kt文件。

  1. class Boy(var name: String) {
  2. fun greeting(): String {
  3. return name + ": hello"
  4. }
  5. }

3.修改Main.java

添加代码调用Boy类中的greeting方法。

  1. public class Main {
  2. public static void main(String[] args) {
  3. Boy boy = new Boy("Tom");
  4. System.out.println(boy.greeting());
  5. }
  6. }


Gradle的任务

Gradle中的project和task

Gradle本身的实体类(又称领域对象)主要有Project和Task,Project为Task提供执行的容器和上下文。Gradle之所以可以工作,是因为在Gradle脚本中将代码以任务的方式插入到了Project中,再由Project来执行这些任务,Gradle就开始工作了。

1.创建

参照前文创建项目名为ProjectAndTask的程序,在build.gradle.kts中创建一个task,代码如下:

  1. task("HelloWorld",{
  2. println("Hello World!")
  3. })

示例中,task方法接受了两个参数,第一个参数("HelloWorld")是任务task的名称,第二个参数(println("Hello World!"))是一个闭包,这个闭包中编写的是kotlin的代码,是实现任务的内容,在示例中表现为输出一段语句。

2.运行

当写完上述代码后,在侧边栏的Gradle中刷新以下,接着会看见other中出现了我们编写的内容,双击可以运行这个任务。

Gradle任务的依赖

依赖管理是指如果一件事没有完成,则下一件事也没法跟着完成,这两件事就被称为有依赖关系。

比如把苹果放入冰箱这一操作,就需要三个步骤:

  1. 打开冰箱门
  2. 放入苹果
  3. 关上冰箱门

如果冰箱门没打开,那么就没法把苹果放入冰箱,这说明步骤2是依赖于步骤1的,这种依赖关系在代码中是靠dependsOn方法来实现的。下面用示例来演示这一过程。

  1. task("opendoor") {
  2. println("打开冰箱门")
  3. }
  4. task("putapple") {
  5. println("放入苹果")
  6. }.dependsOn("opendoor")
  7. task("closedoor"){
  8. println("关上冰箱门")
  9. }.dependsOn("putapple")

当刷新之后,在Gradle侧边栏出现了三个新建的task(opendoor、putapple、closedoor)。在示例中,后两个task都存在依赖关系:putapple依赖opendoor,closedoor依赖putapple, 而运行这三个task的任意一个,都会得到完整的放入苹果操作。

若在Gradle输出中文出现乱码,可以进行如下操作:

在打开的文件最后一行,输入:

-Dfile.encoding=UTF-8

重启IDEA后生效。

Gradle任务的生命周期 

Gradle任务的生命周期分为“扫描时”和“运行时”。

1.扫描时任务

扫描时任务的特点是扫描时所有任务都会执行,任务执行的先后顺序同build.gradle.kts文件中任务代码顺序一致,谁编写在先谁执行,与依赖顺序无关。

  1. task("opendoor") {
  2. println("打开冰箱门")
  3. }
  4. task("putelephant") {
  5. println("放入大象")
  6. }.dependsOn("opendoor")
  7. task("closedoor"){
  8. println("关上冰箱门")
  9. }.dependsOn("putelephant")

运行这三个任务中的任意一个,得到的结果都是相同的,这是因为在Gradle任务的生命周期在扫描阶段时,会根据任务在build.gradle.kts文件中的顺序来依次执行每个任务。

2.运行时任务

Gradle中的任务默认是扫描时任务,若想使用运行时任务,需要添加doFirst高阶函数来实现。

  1. task("opendoor") {
  2. doFirst { println("打开冰箱门") }
  3. }
  4. task("putelephant") {
  5. doFirst { println("放入大象") }
  6. }.dependsOn("opendoor")
  7. task("closedoor") {
  8. doFirst { println("关上冰箱门") }
  9. }.dependsOn("putelephant")

可见在添加doFirst高阶函数后,运行时任务只执行指定的任务,不执行其他无关的任务。 

3.运行时任务与扫描时任务相辅相成

扫描时任务一般是用于声明变量,运行时任务主要是用于执行程序的业务逻辑。

  1. task("login") {
  2. val name = "kotlin"
  3. val pwd = "123"
  4. doFirst {
  5. if (("kotlin" == name) and ("123" == pwd)) {
  6. println("登陆成功")
  7. } else {
  8. println("登陆失败")
  9. }
  10. }
  11. }

在初始化变量时,默认进入了扫描时任务,此时从先到后声明用户名name和密码pwd;在执行task的内部逻辑时,使用了高阶函数doFirst,此时task只执行doFirst中包含的内容,不执行其他无关任务。因此,运行时任务与扫描时任务是相辅相成的。

Gradle任务集

使用task可以声明一个任务,使用tasks可以声明一个任务集。

任务集可以将所有单独的任务放在一个集合中,便于管理多个任务。

  1. tasks{
  2. "opendoor"{
  3. println("打开冰箱门")
  4. }
  5. "putelephant"{
  6. println("放入大象")
  7. }
  8. "closedoor"{
  9. println("关上冰箱门")
  10. }
  11. }

Gradle默认属性和任务

在Gradle项目中有一些默认的属性和任务,这些默认属性存放在build.gradle.kts文件中的properties集合中,properties是项目中所有默认属性组成的一个Map集合,可以通过forEach高阶函数来遍历并获取集合中的key和value的值。

1.输出Gradle项目中的默认属性及对应的值

使用forEach来输出Gradle项目中所有默认属性以及对应的值。

  1. task("showConfig") {
  2. val map = project.properties
  3. map.forEach { (key, value) ->
  4. println("key=$key,value=$value")
  5. }
  6. }

在Gradle中的所有默认属性比较多,因此在运行结果中只显示了部分运行结果的内容。

 2.通过命令行运行任务

之前都是用Gradle侧边栏双击需要运行的任务来执行,这一操作属于图形化界面的操作方式。

在进行操作之前,需要对Gradle进行配置。

(1)配置环境变量

首先在Gradle的官网(Gradle | Releases)下载最新的gradle压缩包。

下载完成后解压到自己设定的目录里,记住这一目录。 

右键此电脑,选择属性,点击左侧边栏中的“高级系统设置”。

弹出界面中,选择“环境变量”。

在弹出界面中,在下方的“系统变量”中编辑变量名为“Path”的值,在值后添加路径,该路径为先前解压gradle压缩包的路径。

在添加好之后,通过快捷键win+r,输入“cmd”回车打开命令提示符窗口,输入“gradle -version”并回车,若正确添加环境变量,将会出现如下输出。

(2)通过命令行执行任务

在IDEA的Terminal窗口输入“gradle showConfig”并回车,就可以通过命令行来执行showConfig任务。

但当使用最新版本的gradle时(本文使用的是8.3),可能会出现冲突无法执行showConfig的情况,冲突的点应该是与build.gradle.kts前文的jcenter()有关。

我的解决方法是使用了较低版本的gradle(gradle 4.1)版本,如果读者有更好的办法欢迎举例。在gradle官网往下滚动便可找到此版本,在使用新版本之后需要对环境变量的路径也进行修改。

若在下方没有找到Terminal窗口,可以在顶部栏中【View】->【Tool Windows】->【Terminal】来打开。 

 除了上述方式,也可以直接在build.gradle.kts文件中,通过defaultTasks设置默认的任务来执行。

  1. task("HelloWorld") {
  2. println("Hello World!")
  3. }
  4. task("showConfig") {
  5. val map = project.properties
  6. map.forEach { (key, value) ->
  7. println("key=$key,value=$value")
  8. }
  9. }
  10. defaultTasks("HelloWorld","showConfig")

若想用命令行窗口执行Gradle项目中的所有默认任务,可以在Terminal直接输入“gradle”回车。 

Gradle增量式更新任务

Gradle的增量式更新会判断哪些文件发生了改变,哪些文件没有发生改变,他只会冲i性能编译发生改变的代码,这样就提高了编译速度。

1.未使用增量式更新

  1. plugins {
  2. java
  3. }
  4. task("updateTask") {
  5. val fileTree = fileTree("src")
  6. val infoFile = file("info.txt")
  7. infoFile.writeText("")//清空数据
  8. fileTree.forEach {
  9. if (it.isFile) {
  10. Thread.sleep(1000)
  11. infoFile.appendText(it.absolutePath + "\r\n")//写入文件
  12. }
  13. }
  14. }

示例中,没有使用增量式更新,每次执行updateTask任务时,都会重新遍历src目录并把目录写入info.txt文件中。

2.使用增量式更新

修改上一示例,增量式更新涉及两个新的API:inputs和outputs,分别对应输入和输出。

修改后,只有输入或输出中有改变,才会执行updateTask任务。

  1. plugins {
  2. java
  3. }
  4. task("updateTask") {
  5. inputs.dir("src")//输入
  6. outputs.file("info.txt")//输出
  7. doFirst {
  8. val fileTree = fileTree("src")
  9. val infoFile = file("info.txt")
  10. infoFile.writeText("")//清空数据
  11. fileTree.forEach {
  12. if (it.isFile) {
  13. Thread.sleep(1000)
  14. infoFile.appendText(it.absolutePath + "\r\n")//写入文件
  15. }
  16. }
  17. }
  18. }

示例中,调用inputs中的dir方法来指定输入目录src,调用putputs中的file方法来指定输出文件info.txt。

Gradle的依赖

Gradle的依赖包管理

在开发中,一个项目可能需要依赖多个jar包,并且jar包之间可能互有关联,而这也导致这些包都需要同时引入。

例如,在使用commons-httpclient-3.1.jar时,还需要使用commons-logging.jar和commongs-codec.jar包。

而在Gradle项目中,只需要添加commons-httpclient-3.1.jar即可,与之关联的jar包会自动关联。

  1. plugins {
  2. kotlin("jvm") version "1.3.61"
  3. }
  4. apply {
  5. plugin("kotlin")
  6. }
  7. dependencies {
  8. compile("commons-httpclient", "commons-httpclient", "3.1")
  9. }
  10. repositories {
  11. mavenCentral()
  12. }

点击Gradle侧边栏的刷新按钮后,可见左侧的Project栏,不仅新增了我们添加的jar包,还一并添加了两个jar包,而他们都是与我们添加的jar包相关联的。


公共仓库和依赖配置

公共仓库

在Gradle项目中,存放开发中常用的一些资源的仓库被称为公共仓库。常用的仓库是Maven Center公共仓库和Jcenter公共仓库,其中Maven Center是目前使用最多的公共仓库。

此处我们就以Maven Center为例,进入Maven Center官网(https://mvnrepository.com/),搜索okhttp。

选中Central,在其中寻找需要的版本。

 此处我选择了最多人使用的版本,因为我们使用的是Kotlin版本的Gradle,所以需要注意选择。

  1. plugins {
  2. kotlin("jvm") version "1.3.61"
  3. }
  4. dependencies {
  5. implementation("com.squareup.okhttp3:okhttp:4.10.0")
  6. }
  7. repositories {
  8. mavenCentral()
  9. }

 示例中dependencies是用于配置依赖仓库中的jar包,repositories用于配置仓库。

依赖配置

Gradle项目的依赖配置分为两个阶段:编译时依赖测试时依赖

在build.gradle.kts中的compile声明的是编译时依赖,testcompile声明的是测试时依赖。

测试时依赖只在测试阶段使用,在项目打包上线不依赖,这样可使项目的体积变小。

注:compile和implementation的区别

compile被称为过时的方法,取而代之的是api和implementation两个依赖指令。

compile(api)是我们最常用的方式,使用该方式依赖的库将会参与编译和打包。

api在使用上和compile完全相同,可直接替换。

implementation特点在于,对于使用了该命令编译的依赖,对该项目有依赖的项目,将无法访问到使用该命令编译的依赖中的任何程序,也就是将该依赖隐藏在内部,而不对外部公开。

  1. plugins {
  2. kotlin("jvm") version "1.3.61"
  3. }
  4. apply {
  5. plugin("kotlin")
  6. }
  7. dependencies {
  8. compile(kotlin("stdlib"))
  9. testCompile("junit", "junit", "4.12")
  10. }
  11. repositories {
  12. mavenCentral()
  13. }

接下来在项目的src/test/java文件夹中创建一个java类,名为Gradle。

  1. public class Gradle {
  2. @Test//通过注解调用junit测试
  3. public void test() {
  4. //断言:当程序执行到断言的位置时,对应的断言应该为真。
  5. // 若断言不为真时,程序会中止执行,并给出错误信息。
  6. Assert.assertEquals(true, 1 == 1);
  7. }
  8. }

 

此时测试通过,若将最后一行的判断修改为1==2,则运行结果如下图所示。


Gradle扩展

Gradle插件自定义扩展

在Gradle官网中,声明了很多系统自带的任务,这些任务有Copy、Delete、Checkstyle等。

接下来展示插件自定义扩展的使用方法。

1.扩展Copy任务,实现将src目录中的文件复制到temp目录中

  1. task("myCopy", Copy::class) {
  2. from("src")
  3. into("temp")
  4. }

from方法用于声明源目录,into用于声明目标目录,若目标目录不存在,会自动生成这个目录。 

2.扩展Delete任务,实现删除temp目录

  1. task("myDelete", Delete::class) {
  2. setDelete("temp")
  3. }

3.扩展Jar任务,将class文件生成Jar包并存放在temp目录

  1. import org.gradle.jvm.tasks.Jar
  2. task("myjar", Jar::class) {
  3. //将out/production/classes目录下的class文件打成jar包存放在temp目录下
  4. from("out/production/classes")
  5. include("**/*.class")
  6. archiveName = "temp/my.jar"
  7. }

include方法主要用于设置文件的类型为class,将out/production/classes目录下的class文件生成my.jar包,并保存到temp目录下。

除了上述任务之外,系统还提供了其他任务,如用JavaCompile来编译Java源码等。开发中需要扩展哪些任务,都可以参考官方文档。

Gradle调用外部扩展

若想在build.gradle.kts文件中执行一段java代码,且这段代码已经写好并生成了一个字节码文件(在java中,被编译器预处理生成的.class文件,被称为字节码文件),此时不想再build.gradle.kts中用groovy或kotlin重写一遍这个代码,而是直接运行。这个时候,Gradle提供了一个闭包Javaexec实现直接运行字节码的功能。

在这个闭包中,main对应的是要运行的类名,classpath对应的是当前的字节码文件存放的位置。

1.生成一个Hello类的字节码

(1)先创建一个名为Order的Gradle项目,在该项目的java文件夹中创建一个Hello类

  1. public class Hello {
  2. public static void main(String[] args){
  3. Systerm.out.println("I am java code");
  4. }
  5. }

(2)修改build.gradle.kts中的内容

  1. plugins{
  2. application
  3. }
  4. application{
  5. mainClassName = "Hello"
  6. }

在Gradle侧边栏中的other文件夹中,双击compileJava可以运行Hello类中的main方法,运行成功后,将会在build/classes/java/main目录下生成Hello.class字节码。 

2.在build.gradle.kts中运行Hello.class字节码 

将生成的Hello.class文件复制到与build.gradle.kts同一目录下,在刚才的build.gradle.kts添加如下内容

  1. task("order"){
  2. //执行java代码
  3. javaexec{
  4. main = "Hello"
  5. classpath(".")
  6. }
  7. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/293395
推荐阅读
相关标签
  

闽ICP备14008679号