[万字长文]一文带你深入了解Android Gradle

作为每一个Android研发,相信对gradle并不陌生,android studio新建每个项目或者module都会自动生成gradle文件,AS默认也是采用Gradle作为构建工具的。

但是apk打包背后是如何gradle产生联系,以及gradle还能为我们平时的开发工作带来哪些帮助并不是都能有时间了解,那么本文就将带大家深入了解Android Gradle。

看完本文,你将了解到这些内容:
1.掌握 gradle 的基本使用
2.了解 gradle 及 android gradle plugin
3.了解 gradle 构建阶段及生命周期回调
4.掌握 Task,Transform 等概念
5.学会自定义 task,自定义 gradle 插件
6.了解 android gradle plugin 的构建流程
7.了解 android gradle plugin 的主要 task 的实现及作用

Part1 Gradle基础知识

1.gradle是什么?

gradle 是一个自动化构建工具,通过组织一系列 task 来最终完成自动化构建,所以 task 是 gradle 里最重要的概念之一,
以打包生成apk 为例,整个过程要经过资源的处理,javac 编译,dex 打包,apk 打包,签名等等步骤,每个步骤就对应到 gradle 里的一个 task。

gradle 可以使用 Groovy 或者 Kotlin DSL编写,这里我们涉及一个概念DSL ,DSL 也就是 Domain Specific Language 的简称,相对应的是 GPL (General-Purpose Language),比如 java语言,与 GPL 相比起来,DSL 使用简单,定义比较简洁,比起配置文件,DSL 又可以实现语言逻辑
对 gradle 脚本来说,通过DSL实现了简洁的定义,又有充分的语言逻辑,以 android {} 为例,这本身是一个函数调用,参数是一个闭包,但是这种定义方式明显要简洁很多

2.gradle中的基本概念

当我们使用每天吃饭的工具As新建一个Android工程时候,我们会看到如下的组成:
[万字长文]一文带你深入了解Android Gradle_第1张图片
如此之多和gradle有关系的文件,那么它们分别是什么作用呢?下面带你一一进行分析

2.1 settings.gradle
settings.gradle 是负责配置项目的脚本,其对应为gradle源码中的Setting.java ,如下图所示
[万字长文]一文带你深入了解Android Gradle_第2张图片
它的Api调用可以参考Setting Api

一般我们接触比较多的如下几个方法:

include(projectPaths)
includeFlat(projectNames)
project(projectDir)

一般在项目里见到的引用子模块的方法,就是使用 include,这样引用,子模块位于根项目的下一级

include ':app'

如果想指定子模块的位置,可以使用 project 方法获取 Project 对象,设置其 projectDir 参数

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

效果如下:
在这里插入图片描述
2.2 rootproject/build.gradle
也就是project根目录下的 gradle,gradle 构建的时候,会根据 build.gradle 生成 Project 对象,Project 其实是一个接口,真正的实现类是 DefaultProject,DefaultProject源码,Project Api

相信下面几个方法,大家在project的.gradle中再熟悉不过了

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

一个Android Project工程的标准配置

buildscript { // 配置项目的 classpath
    repositories {  // 项目的仓库地址,会按顺序依次查找
        google()
        jcenter()
        mavenLocal()
    }
    dependencies { // 项目的依赖
        classpath 'com.android.tools.build:gradle:4.2.1'
        classpath 'com.xx.plugin:xxplugin:0.0.1'
    }
}

allprojects { // 子项目的配置
    repositories {
        google()
        jcenter()
        mavenLocal()
    }
}

2.3 module/build.gradle
子项目和根项目的配置是差不多的,不过在子项目里可以看到有一个明显的区别,就是App module下会自动引入插件 apply plugin “com.android.application”,Library module 会自动引入插件 apply plugin: “com.android.library”

我们常见的子项目build.gradle的属性如下:
compileSdkVersion // 指定编译需要的 sdk 版本
defaultConfig // 指定默认的属性,会运用到所有的 variants 上
buildTypes // 一些编译属性可以在这里配置,可配置的所有属性在 这里
productFlavor // 配置项目的 flavor

2.4 依赖api
我们在gradle中依赖一个库,都会使用到implementation,api等,同时在gradle版本3.4开始,compile被implementation和api取代,provided被provided取代,各api作用如下:
[万字长文]一文带你深入了解Android Gradle_第3张图片
为了让大家更好的理解这几个api的作用,下面举个栗子,项目里有三个模块:app,module1, module2
模块 app 中有一个类 ModuleApi
模块 module1 中有一个类 Module1Api
模块 module2 中有一个类 Module2Api

implementation 依赖
当 module1 使用 implementation 依赖 module2 时,在 app 模块中无法引用到 Module2Api 类
[万字长文]一文带你深入了解Android Gradle_第4张图片
api 依赖
当 module1 使用 api 依赖 module2 时,在 app 模块中可以正常引用到 Module2Api 类
[万字长文]一文带你深入了解Android Gradle_第5张图片
compileOnly 依赖
当 module1 使用 compileOnly 依赖 module2 时,在编译阶段 app 模块无法引用到 Module2Api 类,module1 中正常引用,但是在运行时会报错

[万字长文]一文带你深入了解Android Gradle_第6张图片
同时,通过反编译 apk,可以发现 Module2Api 是没有被打包到 apk 里的

runtimeOnly 依赖
当 module1 使用 runtimeOnly 依赖 module2 时,在编译阶段,module1 也无法引用到 Module2Api

你可能感兴趣的:(android,gradle,android,studio)