Gradle基础学习

Android项目构建工具

Posted by wushiqian on July 22, 2019

Gradle基础学习

简介

  • gradle 是一个自动化构建工具
  • gradle 脚本使用了 groovy 或者 kotlin DSL
  • gradle 基于 groovy 编写,而 groovy 是基于 jvm 语言

settings.gradle

​ settings.gradle 是负责配置项目的脚本 ​ 对应 Settings 类,gradle 构建过程中,会根据 settings.gradle 生成 Settings 的对象。对应的可调用的方法在文档里可以查找

rootproject/build.gradle

​ build.gradle 负责整体项目的一些配置,对应的是 Project 类 ​ gradle 构建的时候,会根据 build.gradle 生成 Project 对象,所以在 build.gradle 里写的 dsl,其实都是 Project 接口的一些方法,Project 其实是一个接口,真正的实现类是 DefaultProject
​ build.gradle 里可以调用的方法在 Project 可以查到

其中几个主要方法有:

  • buildscript // 配置脚本的 classpath
  • allprojects // 配置项目及其子项目
  • respositories // 配置仓库地址,后面的依赖都会去这里配置的地址查找
  • dependencies // 配置项目的依赖

module/build.gradle

​ build.gradle 是子项目的配置,对应的也是 Project 类 ​ 子项目和根项目的配置是差不多的,不过在子项目里可以看到有一个明显的区别,就是引用了一个插件 apply plugin “com.android.application”,后面的 android dsl 就是 application 插件的 extension,关于 android plugin dsl 可以看 android-gradle-dsl
其中几个主要方法有:

  • compileSdkVersion // 指定编译需要的 sdk 版本
  • defaultConfig // 指定默认的属性,会运用到所有的 variants 上
  • buildTypes // 一些编译属性可以在这里配置,可配置的所有属性在 这里
  • productFlavor // 配置项目的 flavor

依赖

在 gradle 3.4 里引入了新的依赖配置,如下:

新配置 弃用配置 行为 作用

implementation compile 依赖项在编译时对模块可用,并且仅在运行时对模块的消费者可用。 对于大型多项目构建,使用 implementation 而不是 api/compile 可以显著缩短构建时间,因为它可以减少构建系统需要重新编译的项目量。 大多数应用和测试模块都应使用此配置。 api 只会暴露给直接依赖的模块,使用此配置,在模块修改以后,只会重新编译直接依赖的模块,间接依赖的模块不需要改动

api compile 依赖项在编译时对模块可用,并且在编译时和运行时还对模块的消费者可用。 此配置的行为类似于 compile(现在已弃用),一般情况下,您应当仅在库模块中使用它。 应用模块应使用 implementation,除非您想要将其 API 公开给单独的测试模块。 api 会暴露给间接依赖的模块,使用此配置,在模块修改以后,模块的直接依赖和间接依赖的模块都需要重新编译

compileOnly provided 依赖项仅在编译时对模块可用,并且在编译或运行时对其消费者不可用。 此配置的行为类似于 provided(现在已弃用)。 只在编译期间依赖模块,打包以后运行时不会依赖,可以用来解决一些库冲突的问题

runtimeOnly apk 依赖项仅在运行时对模块及其消费者可用。 此配置的行为类似于 apk(现在已弃用)。 只在运行时依赖模块,编译时不依赖

flavor

​ flavor,dimension,variant在 android gradle plugin 3.x 之后,每个 flavor 必须对应一个 dimension,可以理解为 flavor 的分组,然后不同 dimension 里的 flavor 两两组合形成一个 variant。

flavorDimensions "size", "color"

productFlavors {
    big {
        dimension "size"
    }
    small {
        dimension "size"
    }
    blue {
        dimension "color"
    }
    red {
        dimension "color"
    }
}

​ 那么生成的 variant 对应的就是 bigBlue,bigRed,smallBlue,smallRed ​ 每个 variant 可以对应的使用 variantImplementation 来引入特定的依赖,比如:bigBlueImplementation,只有在 编译 bigBlue variant的时候才会引入。

gradle wrapper

gradlew / gradlew.bat

​ 这个文件用来下载特定版本的 gradle 然后执行的,就不需要开发者在本地再安装 gradle 了。这样做有什么好处呢?开发者在本地安装 gradle,会碰到的问题是不同项目使用不同版本的 gradle 怎么处理,用 wrapper 就很好的解决了这个问题,可以在不同项目里使用不同的 gradle 版本。gradle wrapper 一般下载在 GRADLE_CACHE/wrapper/dists 目录下

gradle/wrapper/gradle-wrapper.properties

​ 是一些 gradlewrapper 的配置,其中用的比较多的就是 distributionUrl,可以执行 gradle 的下载地址和版本。

gradle/wrapper/gradle-wrapper.jar

​ 是 gradlewrapper 运行需要的依赖包。

gradle init.gradle

​ 在 gradle 里,有一种 init.gradle 比较特殊,这种脚本会在每个项目 build 之前先被调用,可以在其中做一些整体的初始化操作,比如配置 log 输出等等 ​ 使用 init.gradle 的方法:

  1. 通过 –init-script 指定 init.gradle 位置 eg: gradlew –init-script initdir/init.gradle

  2. init.gradle 文件放在 USER_HOME/.gradle/ 目录下

  3. gradle 脚本放在 USER_HOME/.gradle/init.d/ 目录下

  4. gradle 脚本放在 GRDALE_HOME/init.d/ 目录下

gradle 生命周期及回调

gradle 构建分为三个阶段

  • 初始化阶段
    初始化阶段主要做的事情是有哪些项目需要被构建,然后为对应的项目创建 Project 对象
  • 配置阶段
    配置阶段主要做的事情是对上一步创建的项目进行配置,这时候会执行 build.gradle 脚本,并且会生成要执行的 task
  • 执行阶段
    执行阶段主要做的事情就是执行 task,进行主要的构建工作 gradle 在构建过程中,会提供一些列回调接口,方便在不同的阶段做一些事情,主要的接口有下面几个
gradle.addBuildListener(new BuildListener() {
    @Override
    void buildStarted(Gradle gradle) {
        println('构建开始')
        // 这个回调一般不会调用,因为我们注册的时机太晚,注册的时候构建已经开始了,是 gradle 内部使用的
    }

    @Override
    void settingsEvaluated(Settings settings) {
        println('settings 文件解析完成')
    }

    @Override
    void projectsLoaded(Gradle gradle) {
        println('项目加载完成')
        gradle.rootProject.subprojects.each { pro ->
            pro.beforeEvaluate {
                println("${pro.name} 项目配置之前调用")
            }
            pro.afterEvaluate{
                println("${pro.name} 项目配置之后调用")
            }
        }
    }

    @Override
    void projectsEvaluated(Gradle gradle) {
        println('项目解析完成')
    }

    @Override
    void buildFinished(BuildResult result) {
        println('构建完成')
    }
})

gradle.taskGraph.whenReady {
    println("task 图构建完成")
}
gradle.taskGraph.beforeTask {
    println("每个 task 执行前会调这个接口")
}
gradle.taskGraph.afterTask {
    println("每个 task 执行完成会调这个接口")
}

自定义 task

task myTask {
    println 'myTask in configuration'
    doLast {
        println 'myTask in run'
    }
}

class MyTask extends DefaultTask {
    @Input Boolean myInputs
    @Output 
    @TaskAction
    void start() {
    }
}

tasks.create("mytask").doLast {
}

Android transform

​ android gradle plugin 提供了 transform api 用来在 .class to dex 过程中对 class 进行处理,可以理解为一种特殊的 Task,因为 transform 最终也会转化为 Task 去执行 ​ 要实现 transform 需要继承 com.android.build.api.transform.Transform 并实现其方法,实现了 Transform 以后,要想应用,就调用 project.android.registerTransform()

自己写 plugin