Gradle基础知识

前半部分:

build.gradle // 构建脚本文件,主要的构建配置都在这里写

gradle // 存放gradle wrapper 执行配置和工具的文件夹,

gradlew // gradle wrapper 执行脚本文件,用来在没有安装 gradle 的情况下执行 gradle 命令。当然,第一次执行时会下载 gradle。

gradlew.bat // gradle wrapper 执行脚本文件的 windows 版

settings.gradle // 项目配置,指明根项目名字和引入的 module

  1. Gradle Wapper

Gradle Wrapper 它是一个脚本,调用了已经声明的 Gradle 版本,并且我们编译时需要事先下载它。所以,开发者能够快速的启动并且运行 Gradle 项目,不用再手动安装,从而节省了时间成本。

Gradle Wrapper 它是一个脚本,调用了已经声明的 Gradle 版本,并且我们编译时需要事先下载它。

但是这个版本是不是固定死的?

答案是显然的,是可以自定义的

它的结构如上图所示

  1. Gradle的日志

  • ERROR:错误信息

  • QUITE:重要信息

  • WARNING:警告信息

  • LIFECYCLE:进度信息

  • INFO:一般信息

  • Debug:调试信息

其实是靠获取的Logger的实例获取打印的log

task log() {

logger.quiet('1')

logger.error('2')

logger.warn('3')

logger.lifecycle('4')

}

  1. Groovy基础

Groovy是一种跟java极其类似的语言,Groovy是可以跑在JVM上的一种语言

那么Groovy与java的不同?

在Groovy 中;不是必须的

在上面的任务中,笔者一直在用‘’作为字符表达式,但是这种只能是作为字符常量,不能作为运算,用一个例子来看下

单‘’的是不能计算的,双“”是可以计算的,且如果只有一个常量,那就可以省略+

常用的一些语法

1集合

在java里定义对象是要new出来,在Grovvy里并不需要

可以看到在Groovy中,负数也是可以访问到的

但是,如果访问超过了最大数量就会出问题

list也是可以循环遍历的,it 就是一个闭包

那么何为闭包在后面会说到

list操作的具体语法在下面链接中

https://blog.csdn.net/feizuiku0116/article/details/122684315

在本次分享不继续细说,因为与java语法极其相似

也支持add/contains/等一系列

2Map

Map与java里的使用也类似,看下面的例子

map提供了几种访问元素的办法,也提供了遍历方法

map.key map[key]

map操作的具体语法在下面链接中

https://blog.csdn.net/feizuiku0116/article/details/122684328

但是这里有一个笔者比较关注的点,put同样的key会怎么样?

结果是显而易见的,与HashMap特性很类似

3方法

与java 语言很相似,但是Groovy语法里return是可以不写的,参数也可以不写括号,return的参数必须指明,不能以算法返回

代码块可以作为参数传递,Groovy是可以将花括号里的代码作为参数传递的,其实就是所谓的闭包,我们不在这个地方停留,一会闭包里会详细讲

4JavaBean

JavaBean是一个很好的概念,现在的插件化,组件化都基于这个javaBean,Groovy可以很轻松修改JavaBean的属性,而且在Groovy里可以少写很多getset方法

使用 对象名['成员名'] 访问成员 , 相当于执行 getter 方法

5闭包

闭包是Groovy的重要特性,使代码灵活,轻量,可复用

如何理解这段代码?

可以这样想

closure就是传入进来的方法对象,方法对象会执行内部的方法

java也有类似的例子

多个参数就不能使用it作为表达式,就应该使用类似于javalamda的表达式

第二点就是闭包委托

什么是闭包委托?

那么先看一段代码,这段代码说明了什么?

说明了 thisObject的执行优先级最高,为什么?因为当前Context打印出来的对象与thisObject的对象是一样的,那么默认就使用thisObject也就是this来执行方法也就是闭包

而ower和delegate的对象是一样的

这就是所谓委托

  1. Gradle构建脚本的基础

在Gradle中第一步就是settings.gradle一个项目下有可能会有很多的Module,也就是子工程,一个根工程可以有很多的子工程

一个子工程一定要在settings.gradle里配置才能被识别,构建时候包含进去

当我们生成一个Module,Android studio会自动帮我们将Module添加到根目录的settings.gradle里

2Build文件

每一个Project都会有一个builder文件,比如应用插件或者配置Maven仓库,gradle为程序提供了更简洁的配置,比如配置所有的ChildProject为jcenter

除了提供的subprojects之外,还有allprojects

故名思意,就是所有Project的配置

用一个简单的实例来证明一下

2Project和task

一个Gradle有很多Project,而一个Project包含了很多的task

task是一个原子性的操作

task很简单,前面已经有很多例子

task创建方式也很简单

task是有依赖关系的

task3执行时候1和2均被执行

通过api间交互

对于通过直接操纵任务名来操作任务是因为Project把任务注册成了Project的一个属性,而对于我们自己的任务也是Project的一个属性

也可以用类似方法调用

自定义属性,gradle的自定义属性可以有广泛的作用域,可以跨Project

sourceSets还可以进行调整目录结构等工作

sourceSets其他相关API可以去官网文档下看下

3任务

任务的创建

前面已经有很多任务的例子

那么还有什么创建任务的方式?

这些都可以创建任务+闭包+Map+name这些都可以创建任务

还有tasks.create这种方式创建等,前面均有例子

任务都是通过TaskContainer创建的,任务就是Project的一个属性

任务的访问

除了我们已经知道的任务名直接访问外,还可以用tasks["test121"]这种方式访问,核心原理也是a.get()方法

通过路径来访问。访问方式有两种,一种是get,一种是find,区别在于get如果找不到任务会抛出UnKnownTaskException异常,而find在找不到任务时返回null。

由此可见Gradle的灵活性

任务的分组

任务是可以分组和添加描述的。任务分组其实就是对任务分类,便于对任务归类整理。任务的描述就是说明任务有什么用,是任务的大概说明。

<<操作符

在Gradle 5.1后已经废弃。

任务执行的分析

任务是如何执行的?

当我们执行一个任务的时候,其实就是执行其拥有的actions列表。这个列表保存在Task的对象实例中的actions成员变量中,其类型是List。

关于Task执行的源代码不再这里拓展

任务的排序

通过任务的shouldRunAfter和mustRunAfter这两个方法,可以控制一个任务应该或者一定要在某个任务之后执行。

如果一并启用的话就会有先后顺序

任务的启用和禁用

Task中有个enabled属性,用于启用和禁用任务,默认为true,表示启用,设置为false,则禁止任务执行,输出会提示该任务被跳过。

任务的Only断言

task ex47DisenabledTask {

println 'ex47DisenabledTask'

}

ex47DisenabledTask.enabled=false

// 4.8

final String BUILD_APPS_ALL = "all";

final String BUILD_APPS_SHOUFA = "shoufa";

final String BUILD_APPS_EXCLUDE_SHOUFA = "exclude_shoufa";

task ex48QQRelease {

println "打应用宝的包"

}

task ex48BaiduRelease {

println "打百度的包"

}

task ex48HuaweiRelease {

println "打华为的包"

}

task ex48MiuiRelease {

println "打小米系统的包"

}

task build {

group BasePlugin.BUILD_GROUP

description "打渠道包"

}

build.dependsOn ex48QQRelease, ex48BaiduRelease, ex48HuaweiRelease, ex48MiuiRelease

ex48QQRelease.onlyIf {

def execute = false;

if (project.hasProperty("build_apps")) {

Object buildApps = project.property("build_apps")

if (BUILD_APPS_EXCLUDE_SHOUFA.equals(buildApps) || BUILD_APPS_ALL.equals(buildApps)) {

execute = true

} else {

execute = false

}

} else {

execute = true

}

execute

}

ex48BaiduRelease.onlyIf {

def execute = false;

if (project.hasProperty("build_apps")) {

Object buildApps = project.property("build_apps")

if (BUILD_APPS_EXCLUDE_SHOUFA.equals(buildApps) || BUILD_APPS_ALL.equals(buildApps)) {

execute = true

} else {

execute = false

}

} else {

execute = true

}

execute

}

ex48HuaweiRelease.onlyIf {

def execute = false;

if (project.hasProperty("build_apps")) {

Object buildApps = project.property("build_apps")

if (BUILD_APPS_EXCLUDE_SHOUFA.equals(buildApps) || BUILD_APPS_ALL.equals(buildApps)) {

execute = true

} else {

execute = false

}

} else {

execute = true

}

execute

}

ex48MiuiRelease.onlyIf {

def execute = false;

if (project.hasProperty("build_apps")) {

Object buildApps = project.property("build_apps")

if (BUILD_APPS_EXCLUDE_SHOUFA.equals(buildApps) || BUILD_APPS_ALL.equals(buildApps)) {

execute = true

} else {

execute = false

}

} else {

execute = true

}

execute

}

onlyif的断言判断的是在这段代码判断的是当前的包(模拟打包)是否需要执行,如果需要打包就返回值为true,如果不能执行就返回false

4插件

应用二进制插件

什么是二进制插件

如果自己开发的库想给别的项目用,需要把自己的库打包后上传到maven,最后每个项目只要依赖maven库就可以集成,maven插件已经过时,官方推荐使用maven-publish插件来实现将我们的代码发布到 Apache Maven仓库的功能。

这个后面有机会再讲

引用一个本地的插件

可以使用本地插件里的属性,还可以看到,自定义属性里不能使用的场景

还有一些其他的用法

应用的第三方发布的插件

要使用第三方依赖,第一个告诉gradle去哪找到这些依赖,使用什么类型的仓库

这里有个问题,build必须在plugins之前否则会报错

语法部的简单介绍到此为止,接下来是基础的应用

多项目构建(所谓的源码依赖),这里直接以demo为例

首先先在我们要依赖的项目下获取module,首先要把要获取的文件写入到gradle.properties

在我们自己项目进行获取

最后引入到项目当中来,至此源码依赖的简易分析就结束了

分渠道打包

productFlavors和flavorDimensions一定要成对出现否则会报错

打包的时候,打出多个包

1.不同包名

2.不同app名,不同icon

3.代码里同一个变量名,但是对应不同的值

4.根据不同渠道引入不同的sdk,以及不同渠道不同java代码

5.不同渠道,又一个公用的assets文件夹,有私有的assets文件夹

6.不同渠道不同libs文件夹

发布流程

maven-publish 插件

标准式

afterEvaluate {

publishing {

publications {

sha(MavenPublication) {

}

}

}

知识补充

gradle在子模块下定义了gradle的版本请问与根目录的gradle的区别?

gradle自定义的版本在打包的时候还是使用了根目录的gradle

实践出真知,gradle的版本仍然是根目录的7.2而不是子项目的3.3

那么问题来了?有没有办法让我们的代码指定是3.3呢

ext

项目全局属性,多用于自定义,比如把关于版本的信息都利用ext放在另一个新建的gradle文件中集中管理,比如version.gradle,然后apply引用即可,这是较为早期的版本管理方式。

repositories

仓库,比如google()、maven()、jcenter()、jitpack等三方托管平台。

dependencies

当然配置了仓库还不够,我们还需要在dependencies{}里面的配置里,把需要配置的依赖用classpath配置上,因为这个dependencies在buildscript{}里面,所以代表的是Gradle需要的插件。

7.0之后把plugin的配置简化了,由apply+classpath简化为只要apply就可以了。

allprojects

allprojects块的repositories用于多项目构建,为所有项目提供共同所需依赖包。而子项目可以配置自己的repositories以获取自己独需的依赖包。

task clean(type: Delete)

运行gradle clean时,执行此处定义的task。

该任务继承自Delete,删除根目录中的build目录。相当于执行Delete.delete(rootProject.buildDir)。其实这个任务的执行就是可以删除生成的Build文件的,跟Android Studio的clean是一个道理。

implementation指令依赖是不会传递的,也就是说当前引用的第三方库仅限于本module内使用,其他module需要重新添加依赖才能用,使用api指令的话可以传递。(后面也会细讲依赖)

android 这个插件是怎么来的

  • 通过依赖'com.android.application'插件,有了android{}这个配置DSL;

  • 一个项目对应一个Project对象,Project对象里面包含dependencies函数;

  • android{}这个配置DSL点进去就是Project对象里面dependencies这个函数,二者都接收一个闭包;

  • 然后通过DependencyHandler这个类,执行android(Closure configuration)这个闭包并委托给dependencies(Closure configureClosure),也就是Project对象;

  • 最后Gradle在执行阶段去解析这个Project对象并拿到android{}里面的配置参数,后面就是执行Task等等;

后半部分:

问题就是设计的核心,以上这些基础知识,到底在介绍什么?怎么使用?gradle的重要作用就是打包,打包的流程是怎样的?

任何的程序设计都有自己的生命周期

三个构建阶段

Initialization:配置构建环境以及有哪些 Project 会参与构建(解析 settings.build)

Configuration:生成参与构建的 Task 的有向无环图以及执行属于配置阶段的代码(解析 build.gradle)

Execution:按序执行所有 Task

settinggradle

核心是include,表示给指定的项目添加到构建中,它可以指向我们项目包含的module路径,也可以指向硬盘中子项目的绝对路径,这在项目aar和源码切换的时候非常方便,也是编译提速的重要手段之一。

gradle 的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值