美文网首页
认识构建工具 Gradle

认识构建工具 Gradle

作者: tingtingtina | 来源:发表于2020-10-30 17:55 被阅读0次
    目录

    1. 什么是构建工具?

    以前 Android 开发是用 Eclipse, 而 Eclipse 是一种 IDE(Integrated Development Environment,集成开发环境)

    eclipse

    Eclipse 支持 Java 开发,而 Android 又是基于 Java 语言的,因此 Google 开发了一个叫 ADT(Android Developer Tools)的工具。

    从此就可以在 Eclipse 进行 开发、运行、签名、打包等,在某种意义上 ADT 就是我们的构建工具。

    自从 Google 推出 Android Studio 之后,就默认使用 Gradle 来作为构建工具了,并且在 Android Studio 2.2 之后就不再更新 ADT 了。

    那么问题来了, 到底什么是构建工具?

    构建工具是一个把 源代码生成可用的或可执行应用程序的过程 自动化的程序。

    比如 Java 生成 Jar 包,或者在 Android 生成 .apk 的过程中,构建工具会对项目进行 编译、运行、签名、打包、依赖管理等一系列操作。

    2. Java 中的构建工具

    在 Java 语言中,常用的构建工具有 Ant、Maven、Gradle

    2.1 Apache Ant

    Apache Ant (Another Neat Tool)是一个用 Java 编写的开源的跨平台的项目构建工具。

    Ant 不提供依赖管理器,所以需要自己管理外部依赖。但是 Ant 可以和 Apache lvy 很好的集成,lvy 是一个完善且独立的依赖管理器。

    2.1.1 Ant 构建脚本

    Ant 的一个构建脚本由三个基本元素构成:一个 Project、多个 Target 和可用的 Task。

    ant.jpg

    开发者需要显示的指定每一个任务,每个任务包含一组由 XML 编码的指令,必须在指令中明确告诉 Ant 源码在哪里,结果字节码存储在哪里,如何将这些字节码打包成 JAR 文件。Ant 没有生命周期,你必须定义任务和任务之间的依赖,还需要手工定义任务的执行序列和逻辑关系。这就无形中造成了大量的代码重复。

    2.2 Apache Maven

    Maven 是 Apache 组织下的一个跨平台的项目管理工具,它主要用来帮助实现项目的构建、测试、打包和部署。

    Ant 的灵活性、不便于维护,Maven 选择了约定优于配置的思想,提供了标准的软件生命周期模型和构建模型,通过配置就能对项目进行全面的管理。Maven 将构建的过程抽象成一个个的生命周期过程,在不同的阶段使用不同的已实现插件来完成相应的实际工作,这种设计方法极大的避免了设计和脚本编码的重复,极大的实现了复用。

    Maven 不仅是一个项目构建工具还是一个项目管理工具。它有约定的目录结构和生命周期,项目构建的各阶段各任务都由插件实现,开发者只需遵照约定的目录结构创建项目,再配置文件中生命项目的基本元素,Maven 就会按照顺序完成整个构建过程。Maven 的这些特性在一定程度上大大减少了代码的重复。

    2.3.1 Maven 默认目录布局

    Maven default layout

    2.3.2 生命周期

    Maven 基于构建生命周期的思想。每个项目都确切知道有哪些步骤去执行构建、打包和发布应用程序。

    在构建生命周期每一个步骤都是一个阶段,这些阶段会被有序地执行。

    下图展示了Maven 构建所预定义的阶段和他们执行的顺序。

    Maven build lifecycle

    2.3.3 构建脚本

    Maven 构建脚本样例,名字是 pom.xml,这里要遵循默认约定,所以 Maven 会去 src/main/java 目录中找源代码

    这里指定了一个依赖,声明的类库和传递的依赖会有 Maven 的依赖管理器下载。Maven 预配置从 Maven Center 下载依赖。指定其坐标即可。

    2.3 Gradle

    其中 Ant 和 Maven 都是基于 xml 来进行描述的,xml 是非常好的层级数据描述语言,但对于描述程序流程和构建逻辑却存在很多不足之处,随着构建脚本的复杂度增加,维护构建代码也越来越困难,脚本也越来越臃肿。

    Gradle 是基于 JVM 构建工具的新一代版本

    Gradle 使用的是一种基于 Groovy 的领域特定语言(DSL,Domain Specific Language),Groovy 是一门 JVM 语言,它提供了 Java 的语法糖。由于 Groovy 是在 Java 的基础上做了很多改进,所有 Java 语言的特性 Groovy 都支持,但是用起来更加灵活。所以完全可以混写 Java 和 Groovy。

    DSL:直接点来讲,其实就是这个语言不通用,只能用于特定的某个领域,俗称“小语言”。因此DSL也是语言。

    语法糖: 指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

    • 约定灵活
    • 强大的依赖管理
    • 可扩展的构建
    • 具有表达性的语言和强大的 API
    • 和其他构建工具的集成

    3. Gradle 构建脚本

    友情提示:本次关于 Gradle 的学习主要是为了学习在 Android Studio 上的使用,所以关于 Gradle 的下载安装就不做赘述,从官网下载,安装,配置变量即可。

    每个 Gradle 构建包括三个基本的构建块:项目(projects)、任务(task)和 属性(properties)。每个构建至少包括一个项目,一个项目包括一个或多个任务,项目和任务都是有很多属性来控制构建过程。

    3.1 项目 Project

    每个 Gradle 构建都是以一个脚本开始的。Gradle 构建默认脚本的名字是 build.gradle。当在执行 gradle 命令时,Gradle会去寻找名为 build.gradle 的文件。

    每个 Gradle 脚本至少定义一个 project。当开始构建过程后, Gradle 基于配置实例化 org.gradle.Project 类,并且能够通过 project 变量使其隐式可用。下图是 Project 类的 API 接口和重要的方法。

    img

    一个项目可以创建新的任务(task)、添加依赖(dependencies)和配置(configurations)、应用插件和其他脚本。很多属性比如 name 和 description 都可以通过 getter 和 setter 方法来访问。

    Gradle 支持多项目构建,随着软件系统的复杂, 可以分解成一个个功能性模块,模块之间可以相互依赖,而每个模块也都有自己的独立的 build.gradle 脚本。

    3.2 任务 Task

    task 是 独立原子性工作,一个动作就是任务的原子工作

    很多时候一个任务需要在另一个任务之后执行,尤其是当一个任务的输入依赖于另一个任务的输出时,比如项目打包成 JAR 文件之前先要编译成 class 文件,来看下 Gradle API 中任务的表示:org.gradle.api.Task 接口。

    Task

    从 Hello World 开始了解,

    在 build.gradle 中,定义一个独立的原子性工作,task。

    task helloWorld {
        doLast {
            println("Groovy")
        }
    
        doFirst {
            print("Hello ")
        }
    }
    

    运行该 task:

    $ gradle helloWorld
    输出 :Hello Groovy
    

    通过 -q 定义可选命令行选项 quiet,告诉 Gradle 只输出该 task 相关的信息

    列出所有可用的 task gradle -q tasks

    3.3 属性

    每个 Project 和 Task 实例都提供了 setter 和 getter 方法来访问属性,比如:

    task helloWorld {
        description = "This is a task."
        println(helloWorld.description)
    }
    

    3.4 外部属性

    外部属性一般存储在键值对当中,要添加一个属性,需要用 ext 命名空间。

    ext {
        aValue = 123
    }
    
    task helloWorld {
        println project.ext.aValue
    }
    

    运行任务会输出 123

    外部属性也可以定义在一个属性文件当中。通过 /gradle 或者根目录下的 gradle.properties 文件来定义属性,这些属性可以通过 project 实例来访问。 注意/.gradle目录下只能有一个 Gradle 属性文件,哪怕是有多个项目。 在这份属性文件生命的属性对所有项目可用

    在 gradle.properties 中定义个属性

    testValue = 1234
    

    在项目中可以访问这个变量

    task helloWorld {
        println project.testValue
        println "test : $testValue"
    }
    

    3.5 依赖

    Gradle DSL 配置 dependencies 用来给配置添加一个多或多个依赖,Gredle支持各种不同类型的依赖

    类型 描述
    外部模块依赖 依赖仓库中的外部类库,包括她所提供的元数据
    项目依赖 依赖其他 Gradle 项目
    文件依赖 依赖文件系统中的一系列文件
    客户端模块依赖 依赖仓库中的外部类库,具有生命元数据的能力
    Gradle 运行时依赖 依赖 Gradle API 或者封装 Gradle 运行时的类库

    每个 Gradle 项目都有 DependencyHandler 接口实例, 可以通过 getDependencies() 方法来获取依赖处理器的引用。

    表格中的每种依赖类型都是通过项目的 dependencies 配置块中的依赖处理器的方法来声明的。每个依赖都是 Dependency 类型的一个实例,group、name、version 和 classifier 这几个属性明确标识了一个依赖。

    DependencyHandler

    3.5.1 外部模块依赖

    在 Gradle 中,外部类库通常以 Jar 文件形式存在,被称为外部模块依赖。表示依赖的模块在项目结构之外。其特点是在仓库中能够通过属性明确的标识。

    dependencies {
        api 'io.reactivex.rxjava2:rxandroid:2.1.0'
    }
    

    Gradle 不会指定默认的仓库,要使用这个类库还要指定使用的仓库,下面代码块表示使用 Maven Central 下载依赖。

    repositories {
        mavenCentral()
    }
    

    动态版本声明

    如果想使用一个依赖的最新版本,可以使用占位符 last.integration,比如声明 Rxjava 的最新版本

    dependencies {
        api 'io.reactivex.rxjava2:rxandroid:latest-integration'
    }
    

    或者使用一个 + 号来动态声明版本

    dependencies {
        api 'io.reactivex.rxjava2:rxandroid:2.+'
    }
    

    不过动态版本最好少用或者不用,可靠的和可重复的构建是最重要的。选择新版本的类库可能会导致构建失败。更糟糕的是,可能在不知情的情况下,引入了不兼容的类库版本和副作用,这样也很难知道原因。所以,声明确切类库版应该成为惯例。

    3.5.2 文件依赖

    文件依赖也很常见,比如我们把一个 JAR 包放在 lib 目录下,就是文件依赖

    dependencies {
        api fileTree(include: ['*.jar'], dir: 'libs')
    }
    

    3.5.3 项目依赖

    在多项目构建时,可以声明项目依赖,配置 compile 是 Java 插件提供的,比如下面代码块,声明编译时依赖的项目

    dependencies{
        complie project(':model')
    }
    

    3.6.1 Maven 仓库

    Maven 仓库是 Java 项目中最常用的仓库类型之一,在构建脚本声明一个依赖时,其属性可以用来获取它在仓库的确切位置。(Maven 仓库)

    image

    RepositoryHandler 接口提供了两个方法运行第一预配置的 Maven 仓库 mavenCentral() 和 mavenLocal()

    • Maven Central 仓库,使用 mavenCentral() 方法用来将 Maven Central 引用添加到一系列仓库中

    • 本地 Maven 仓库,使用 mavenLocal() 方法用来在文件系统中关联一个本地的 Maven() 仓库

    • 添加自定义的 Maven 仓库

     repositories {
         mavenCentral()
         mavenLocal()
         maven {
             name 'Custom Maven Repository',
             url 'http://repository.forge.cloudbees.com/release/')
         }
     }
    

    https://mvnrepository.com/repos

    4.Gradle 包装器

    Gradle Wrapper

    只能在自己的机器跑?

    一个项目使用了 Gradle,在其他人使用这个项目的时候,还要安装 Gradle。不同的 Gradle 版本有不同特性,还要询问你安装了哪个版本的 Gradle,怎么运行, Mac 和 Windows 安装有什么区别。因为在本机上运行成功再其他机器上运行失败,太平常了。

    针对这个问题,Gradle 提供了一个方便而使用的解决方案,就是 Gradle 包装器。它能够让机器在没有安装 Gradle 运行的情况下运行 Gradle 构建(PS:在使用 AS 的时候,我们没有专门安装过 Gradle 吧,就是因为有这个 Gradle Wrapper)

    Gradle 包装器让构建脚本运行在一个指定的 Gradle 版本上。它中心仓库自动下载 Gradle 运行的时候,解压再构建。 目标就是创建可靠的、可复用的、与操作系统、系统配置或Gradle版本无关的构建。

    4.1配置包装器

    配置包装器,只需做两件事:创建一个包装器 和 执行任务生成包装器文件


    image

    gradleVersion 指定了想要使用的 Gradle 版本,任务执行之后,会在构建脚本同级目录下看到包装器文件

    image

    (PS:这个层级看起来也很眼熟哈,没错,AS 里面默认使用 Gradle 构建,这些都为我们做好了。)

    包装器提供了名为 gradlew 的脚本,使用他们运行构建和使用已安装好的 Gradle 运行构建是一样的。

    • gradle-wrapper.jar 是 Gradle Wrapper 的主体功能包,包含下载 Gradle 版本的代码。
    • gradle-wrapper.properties Wrapper 运行时的配置文件,文件主要指定了该项目需要从哪里下载什么版本的 Gradle,下载后放到哪里。
    • gradlew,gradlew.bat 使用Wrapper 执行构建的 shell 脚本 和 Windows 批处理文件

    4.2 Wrapper 的工作流程

    gradle-wrapper.properties

    distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    

    4.2 Wrapper 的工作流程

    The Wrapper workflow

    在我们使用 Gradle 构建的时候,如果没有 Gradle 那么先下载 Gradle 的发行版(从 distributionUrl 这个地址去下载,下载到指定路径 Base+Path)中,下载完成之后,再进行 Gradle 构建直接使用即可。再来看这个文件下的几个属性就很清楚了

    • distributionBase
    • distributionPath
    • zipStoreBase
    • zipStorePath
    • distributionUrl 要下载的 gradle 地址以及版本,gradle-wrapper 会先去 wrapper/dists 目录去找,如果没有对应的版本就会下载。

    在 IDEA 的 Settings 有配置根目录 ,所以下载的 Gradle 版本一般在用户目录下的.gradle/wrapper/dists 存放


    5. 多项目构建

    比如在 Android 的开发中也会用模块化结构来分离业务逻辑,每一个模块都可以作为一个单独的项目来看待。在多项目构建中是通过 settings 文件来声明子项目(模块)的。

    5.1 Settings 文件

    settings 文件声明了所需的配置来实例化项目的层次结构。在默认情况下,这个文件被命名为 settings.gradle,并且和 build.gradle 文件放在一起。

    若想使每个子项目都成为构建的一部分,可以调用带有项目路径参数的 include 方法。比如

    //参数是项目路径,不是文件路径
    include 'model'
    include 'repository', 'web'
    

    上面代码中所提到的项目路径是相对于根目录的项目目录。也可以构建更深层次的项目结构。使用冒号(:)来风格每个子项目的层次结构。

    include ':app'
    

    Settings API


    img

    我们也常用这样的写法来指定模块的目录

    include ':skinLibrary'
    project(':skinLibrary').projectDir = new File('libThirdParts/skinLibrary')
    

    5.2 子项目配置

    在 3.1 介绍了一些 Project API 的属性和方法,同时这个 API 为实现多项目构建也提供了相关的方法。

    image

    Project API 提供了 allprojects 和 subprojects 方法来定义所有项目或者只有子项目的一些逻辑。

    比如:

    image

    你可以用 allprojects 方法给所有的项目添加属性,由于根项目不需要 Java 插件,你可以使用 subprojects 给所有子项目添加 Java 插件,如下所示:

     allprojects {
            group = 'com.manning.gia'
            version = '0.1'
        }
    
        subprojects {
            apply plugin: 'java'
        }
    
        project(':repository') {
            dependencies {
                compile project(':model')
            }
        }
    
        project(':web') {
            apply plugin: 'war'
            apply plugin: 'jetty'
    
            repositories {
                mavenCentral()
            }
    
            dependencies {
                compile project(':repository')
                providedCompile 'javax.servlet:servlet-api:2.5'
                runtime 'javax.servlet:jstl:1.1.2'
            }
        }
    

    5.3 子项目的配置文件

    如果多项目构建只有一个 build.gradle 文见 和 settings.gradle,随着项目中的子项目越来越多,那么构建文件也越来越难维护,所以可以为每个项目创建单独的 build.gradle

    根目录的 build.gradle 只保留公共配置块即可

    allprojects {
        group = 'com.manning.gia'
        version = '0.1'
    }
    subprojects {
        apply plugin: 'java'
    }
    

    repository 子项目的构建代码:

    dependencies {
        compile project(':model')
    }
    

    6. 参考资料

    书籍《实战 Gradle》在线阅读英文版(需梯子)
    stormzhang 的公众号 给 Android 初学者的 Gradle 知识普及

    相关文章

      网友评论

          本文标题:认识构建工具 Gradle

          本文链接:https://www.haomeiwen.com/subject/llivzhtx.html