1.背景和意义
先后经历过多个Android开发团队,每个团队都有这样的一个人。他能在gradle中配置一些代码。导致最终的apk 根据品牌+渠道 命名。甚至还能根据不同品牌,配置不同的变量。根据不同变量展示不同界面。gradle除了能帮我们做上述的事之外,还能做哪些呢?
- hook Android 编译过程
- 配置和改善 Gradle 编译速度
学习完gradle,对android 项目的构建理解会更加深入;更加熟练的使用task,帮助我们构建项目
2.概念
gralde它就是一个构建工具,帮助我们编译,打包,发布,检查代码格式,下载jar包等等。它是基于groovy语言编写的。
问题1: android如何自动下载gradle
android 项目创建的时候,gradle文件中自带gradle-wrapper.jar
这个jar包会根据gradle-wrapper.properties
的配置 下载对应的gradle 版本。
问题2: ./gradlew
和gradle
的区别
gradlew就是对gradle的包装和配置,gradlew是gradle Wrapper,Wrapper的意思就是包装。 因为不是每个人的电脑中都安装了gradle,也不一定安装的版本是要编译项目需要的版本,那么gradlew里面就配置要需要的gradle版本
问题3:什么是Project, 什么是Task,什么是Extension
android studio 每个module都有一个build.gradle文件,对于这个build.gradle而言,project 就是我们的module。可以通过 gradle projects
查看Project。
Extension 对我而言就是配置,初始化变量,这个变量的作用就是为Task提供参数。
Task 任务,也是Action,表示这个任务是行为。例如assembleRelease
是一个Task,用来执行打包操作。打完的apk存放路径这个路径可以人为的配置。这个配置,在我看来就是拓展(Extension )
问题4:什么是Gradle Daemon
Gradle Daemon
是gralde的守护进程。是一个长时间运行在后台的进程,避免频繁的初始化。并且 Gradle 会将 Project data 缓存在内存中,加快构建速度。使用Gradle Daemon 是没有任何副作用的,并且我们可以非常简单的使用它,不需要任何成本,Gradle Daomen 对我们用户是完全透明的。可以通过gradle --stop
停止
问题4:什么是闭包Closure
Groovy中的闭包是一个开放,匿名的代码块,可以接受参数,返回值并分配给变量。如:
//定义一个代码块
def innerClosure = {
printf("hello world")
}
//执行方式1
innerClosure()
//执行方式2
innerClosure.call()
闭包也能传递参数:
def innerClosure = {String s,Student student ->
printf(s+student.toString())
}
innerClosure("hello world",new Student("chips","26"))
以上就是gralde的基本知识和概念
3.生命周期
gradle 的生命周期分为三个阶段:
- 初始化阶段
- 配置阶段
- 执行阶段
3.1 初始化阶段
在初始化阶段,Gradle的主要任务是确定有哪些工程参与构建,会解析settings.gradle文件,为文件中参与构建的的项目都创建project对象。可以通过gradle init
完成
3.2 配置阶段
在这个阶段,Gradle会分别在每个Project对象上执行对应的build.gradle脚本,对Project进行配置。gradle提供了俩个方法
void beforeEvaluate(Closure closure) //Project 配置之前调用
void afterEvaluate(Closure closure) //在 Project 配置结束后调用
其中需要注意的是:beforeEvaluate 必须在父模块的 build.gradle 对子模块进行配置才能生效,因为在当前模块的 build.gradle 中配置,它自己本身都没配置好,所以不会监听到。
3.3 执行阶段
在配置时,Gradle 决定了在执行阶段要运行的 task 的顺序,他们的依赖关系的内部结构被建模为一个有向无环图,我们可以称之为 taks 执行图,它可以用 TaskExecutionGraph 来表示。可以通过 gradle.taskGraph 来获取。
在 TaskExecutionGraph 中也可以设置一些 Task 生命周期的回调:
- addTaskExecutionGraphListener(TaskExecutionGraphListener listener)
- addTaskExecutionListener(TaskExecutionListener listener)
- afterTask(Action action),afterTask(Closure closure)
- beforeTask(Action action),beforeTask(Closure closure)
- whenReady(Action action),whenReady(Closure closure)
4. 基础使用
4.1 Task的基础使用
task使用的官方文档:官方文档
build.gradle
中task的定义:
task taskName(){
//任务执行前
doFirst {
println "doFirst"
}
//任务执行完毕的打印
doLast {
println "doLast"
}
}
dependsOn
使用
task任务经常存在相互依赖关系。A task 依赖于 Btask 可以借助dependsOn
。在hook的时候用的比较多
task B {
println "this is a task B"
}
task A(dependsOn: B) {
println "this is a task A"
}
type
使用
type用来表示创建的task 的类型
class MyTask extends DefaultTask {
public String message
public void test(String s) {
println("this is MyTask " + message)
}
}
task testDe(type: MyTask) {
message = "chips"
println test()
}
task之间存在顺序性,使用到的api:mustRunAfter()
和shouldRunAfter()
task B {
println "this is a task B"
}
task A(dependsOn: B) {
println "this is a task A"
}
A.mustRunAfter(B)
这样运行A任务的话,也会顺带执行B任务
自定义插件注册Task的方式:
class MyPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
MyTask t = project.tasks.register("MyTask", MyTask).get()
t.message="chips"
println t.toString()
}
}
ps:千万别用project.getByName("MyTask")
直接获取task,gradle编译出错
以上就是Task的基本用法,下面说说Extension的用法.
4.2 Extension 用法
什么是Extentsion?
就是 Gradle 的 Extension,翻译成中文意思就叫扩展。它的作用就是通过实现自定义的 Extension,可以在 Gradle 脚本中增加类似 android 这样命名空间的配置,Gradle 可以识别这种配置,并读取里面的配置内容。
一般我们通过ExtensionContainer来创建Extension,这个类跟TaskContainer命名有点类似。TaskContainer是用来创建并管理Task的,而ExtensionContainer则是用来创建并管理Extension的,通过Project的以下API可以获取到ExtensionContainer对象
在开始学习前,我们先看一个问题:
android app的build.gradle中 有这样的一段配置:
android {
compileSdkVersion 31
def versionCodeValue = 1
def versionNameValue = "1.0"
}
这个android{} 就是一个名为android的Extension 。
我们来看看android这个Extension是如何定义的,系统源码连接:AppPlugin
AppPlugin插件:
@Override
void apply(Project project) {
super.apply(project)
....
extension = project.extensions.create('android', AppExtension,
this, (ProjectInternal) project, instantiator,
buildTypeContainer, productFlavorContainer, signingConfigContainer)
}
注册了一个名为android拓展,类型是AppExtension.
AppExtension:
public class AppExtension extends BaseExtension {
final NamedDomainObjectContainer<DefaultProductFlavor> productFlavors
final NamedDomainObjectContainer<DefaultBuildType> buildTypes
final NamedDomainObjectContainer<SigningConfig> signingConfigs
private final DefaultDomainObjectSet<ApplicationVariant> applicationVariantList =
new DefaultDomainObjectSet<ApplicationVariant>(ApplicationVariant.class)
}
productFlavors/signingConfigs/buildTypes 分别是我们在build.gradle android下面配置的内容。他们都是一个又一个的拓展。用来配置参数,给Task的执行提供参数。
AppExtension 还有哪些拓展,可以访问AppExtension官网 看看还有哪些拓展可以写
使用Extension 分为三步:
- 定义Extension 的参数类型
- 在build.gradle中注册这个Extension
- 实例化拓展,且给每个元素赋值
- 定义一个Extension 类型
class MyExtension{
String name
String age
}
2.注册Extension
getExtensions().create("MyExtension_拓展名称", MyInfoExtension)
3.在build.gradle 使用:
myExtension {
name = "wxy"
age = "123"
}
如何访问myExtension 呢?
project.afterEvaluate {
MyInfoExtension mMyInfoExtension = getExtensions().getByName("myExtension")
println "Extension 使用: "+mMyInfoExtension.name+" "+mMyInfoExtension.age
}
以上就是Extension 基本应用.
如何定义像android{}这样的Extension呢?
class Address{
public String address
}
class MyExtension {
public String name
public String age
public Address addressInfor=new Address();
// 配置方法
void addressConfig(Action<Address> action) {
action.execute(addressInfor) // 直接执行 action 参数的 execute 方法,并传入扩展对象
}
}
其中addressConfig 是必填项.
这样在build.gradle中就可以这样定义了 :
getExtensions().create("myExtension", MyExtension)
myExtension {
name = "chips"
age = "123"
addressConfig{
address="湖北"
}
}
我们还可以在.groovy文件中,调用:
class MyPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.getExtensions().create("MyInfoExtension",MyInfoExtension)
}
}
这一步做完之后,相当于我们注册了这样一个拓展。那么直接在buid.gradle中 进行声明就行.
4.3 属性的访问
属性的访问我遇到的有三种方式:
- 根 build.gradle 中定义变量
- 导入其他的.gradle,携带的变量
- 访问gradle.properties
- 访问local.properties
- 根build.gradle 定义的变量,其他的子build.gradle中都能访问。如:
project.ext {
versionCode2=2021
}
project.ext 传入一个闭包,返回一个Defaultextrapropertiesextension 拓展,此类实际上是用一个Map保存变量的。
- 导入其他的.gradle
类似定义constants.gradle
project.ext {
min_sdk_version = 24
compile_sdk_version = 'android-31'
target_sdk_version = 31
build_tools_version = "30.0.3"
java_Compatibility = JavaVersion.VERSION_1_8 // 支持lambda
}
然后在build.gradle中
apply from: "${rootProject.projectDir}/constants.gradle"
3.gradle.properties 访问
在gradle.properties中定义各种变量 如:
versionCode5=2022
在build.gradle中就可以这样使用:
defaultConfig {
versionCode versionCode5 as int
}
必须得用as 转换成对应的类型,不然会报错
4.local.properties 访问
local元素的访问稍微麻烦点.得new 一个Properties 对象,指定加载的文件
Properties properties = new Properties()
if (project.rootProject.file('local.properties').exists()) {
properties.load(project.rootProject.file('local.properties').newDataInputStream())
}
---
properties.getProperty("versionCode3") as int
之后通过properties.getProperty("versionCode3") as int 得到值。响应的也一定要加上as int,默认是string类型
以上就是gradle的基础知识。下一节讲Gradle的自定义插件