作为每一个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 的实现及作用
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 {} 为例,这本身是一个函数调用,参数是一个闭包,但是这种定义方式明显要简洁很多
当我们使用每天吃饭的工具As新建一个Android工程时候,我们会看到如下的组成:
如此之多和gradle有关系的文件,那么它们分别是什么作用呢?下面带你一一进行分析
2.1 settings.gradle
settings.gradle 是负责配置项目的脚本,其对应为gradle源码中的Setting.java ,如下图所示
它的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作用如下:
为了让大家更好的理解这几个api的作用,下面举个栗子,项目里有三个模块:app,module1, module2
模块 app 中有一个类 ModuleApi
模块 module1 中有一个类 Module1Api
模块 module2 中有一个类 Module2Api
implementation 依赖
当 module1 使用 implementation 依赖 module2 时,在 app 模块中无法引用到 Module2Api 类
api 依赖
当 module1 使用 api 依赖 module2 时,在 app 模块中可以正常引用到 Module2Api 类
compileOnly 依赖
当 module1 使用 compileOnly 依赖 module2 时,在编译阶段 app 模块无法引用到 Module2Api 类,module1 中正常引用,但是在运行时会报错
同时,通过反编译 apk,可以发现 Module2Api 是没有被打包到 apk 里的
runtimeOnly 依赖
当 module1 使用 runtimeOnly 依赖 module2 时,在编译阶段,module1 也无法引用到 Module2Api