Gradle是一个非常优秀的构建系统工具,它的DSL基于Groovy实现。
grdle需要Java环境,要求JDK 6 以上,并且要配置Java的环境变量。
Gradle文件说明
官网下 https://gradle.org/ 载,得到压缩包 gradle-2.14.1-all.zip 。然后解压。得到目录清单
1.docs API DSL 指南文档
2.getting-started.html
3.init.d gradle初始化脚本目录
4.lib
5.LICENSE
6.media icon 资源
7.NOTICE
8.sample 示例
9.src 源文件
然后把GRADLE_HOME/bin添加环境变量路径里。
执行:
gradle -v 可以查看是否安装成功。
如果要在AS里执行,记得重启AS.
task hello{
doLast{
println "hello world"
}
}
执行命令:gradle -q hello
-q 参数用于控制gradle输出的日志级别
是对gradle的包装,便于团队开发过程中统一Gradle构建的版本。这样大家可以使用统一的Gradle版本进行构建。wrapper在window下一个处理脚本,在linux下是一个shell脚本。他会检查Gradle有没有被下载关联。
gralde wrapper
distributionBase=GRADLE_USER_HOME 主目录
distributionPath=wrapper/dists 相对distributionBase的路径
zipStoreBase=GRADLE_USER_HOME 同distributionBase
zipStorePath=wrapper/dists
distributionUrl=https://services.gradle.org/distributions/gradle-6.5-bin.zip Gradle发行版压缩包的下载地址。
gradle-wrapper.properties由wrapper task生产的。我们可以自定义wrapper task任务来达到配置gradle-wrapper.properties。
task wrapper(task:Wrapper){
gradleVersion = '2.4'
}
distributionBase=GRADLE_USER_HOME
//下载gradle的路径
distributionUrl=https://services.gradle.org/distributions/gradle-6.7.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
ERROR
QUIET
WARNING
LIFECYCLE 进度消息
INFO
DEBUG
输入Quiet级别之上的日志
gradle -q tasks
默认情况下,堆栈信息是关闭的。需要我们通过命令行的堆栈信息开关打开它。
-s or --stacktrace 输出关键性信息
-S or --full-stacktrace 输出详细信息
logger.quiet("")
logger.error("")
./gradlew 是Mac的命令,如果你是window,输入gradle
使用帮助
./gradlew -?
./gradlew -h
./gradlew -help
强制刷新依赖
./gradlew --refresh-dependencies assemble
多任务调用
有时候我们要同时运行多个任务,比如执行jar之前,先clean
./gradlew clean jar
通过任务名字缩写执行
比如有个任务connectCheck
可以执行:
./gradlew cc
Groovy是基于JVM的一种动态语言,Groovy完全兼容Java,有在此增加很多动态类型和灵活的特性。如 闭包 DSL
Groovy不需要分号,单引号和双引号都可以。
def str1 = "hello"
def str2 = 'hello'
单引号没有运算能力,表示常量字符串。双引号可以直接运行表达式计算。
task testStr{
def name = "lisi"
println '单引号的变量计算:${name}'
println "双引号的变量计算:${name}"
}
单引号的变量计算:${name}
双引号的变量计算:lisi
Groovy完全兼容Java的集合,且进行了扩展。
list set map Queue
list
def numlist = [1,2,3,4] 使用索引访问集合
println numlist.getClass().name
println numlist[1] 获取第二个元素
println numlist[-1] 访问最后一个元素
println numlist[1..3] 访问第二个到第四个元素
numlist.each{
println it
}
map
def map = ['width':1024,'height':768]
println map['width'] 获取width
println map.height 获取值
map.each{
println "key:${it.key},Value:${it.value}"
}
groovy还提供了collect、find、findAll
def method(int a,int b){
println a+b
}
task invokeMethod<<{
method(1,2)
method 1,2 //括号可以省略
}
return 可以不写,最后一句作为返回值。
代码块是可以作为参数传递的
numlist.each({println it})
class Person{
private String name
}
task hellJava <<{
person p = new Person()
p.name ="lisi"
println "名字是:${p.name}"
}
闭包就是一段代码块
task helloClosure<<{
customEach{
print it
}
}
//closure参数用于接收闭包(代码块)
def customEach(closure){
for (i in 0..<10) {
closure(i)
}
}
我们为闭包传递了两个参数,key .value
task helloClosure {
eachmap { K, V ->
println "$K $V"
}
}
def eachmap(closure) {
def map = ["one": 1, "two": 2]
map.each {
closure(it.key, it.value)
}
}
闭包的强大之处在于支持闭包方法的委托。Groovy的闭包有thisObject、owner、delegate三个属性。
当你在闭包内调用方法时,有它们来确定使用哪个对象来处理。默认delegate/owner是相等的。但是delegate可以被修改的。Gradle中的闭包的很多功能都是通过修改delegate实现的。
task helloDelegate {
new Delegate().test {
println "thisObject:${thisObject.getClass()}"
println "owner:${owner.getClass()}"
println "delegate:${delegate.getClass()}"
method1()
it.method1()
}
}
def method1() {
println "context this:${this.getClass()} in root"
println "method1 in root"
}
class Delegate {
def method1() {
println "Delete this:${this.getClass()} in Delegate"
println "method1 in Delegate"
}
def test(Closure<Delegate> closure) {
closure(this)
}
}
result:
thisObject:class build_9eq7gfn6et0rl6qz17rvoqogw
owner:class build_9eq7gfn6et0rl6qz17rvoqogw$_run_closure2
delegate:class build_9eq7gfn6et0rl6qz17rvoqogw$_run_closure2
context this:class build_9eq7gfn6et0rl6qz17rvoqogw in root
method1 in root
Delete this:class Delegate in Delegate
method1 in Delegate
thisObject的优先级最高。默认情况下,优先使用thisObject来处理闭包中调用的方法,如果有则执行。thisObject其实就是这个构建脚本的上下文,它和脚本中的this对象是相等的。
列子中也证明delegate和owner是相等的,两个的优先级是:owner比delefate高。所以闭包内方法的处理顺序是:thisObject>owner>delegate。
DSL (domain specific Language)领域特定语言。专注某个领域的语言。Gradle就是一个DSL.基于Groovy,专门解决自动化构建的DSL.
用于初始化及工程树配置。为了配置子工程。
子工程只有在settting文件里配置了才能识别、
每个project都会有一个build.gradle文件,它是project构建入口,配置版本,依赖库,配置插件。
Root Project也可以获取所有child project,比如Java在开发大型项目的时候,会有很多模块,每个模块都是project。
subprojects {
apply plugin "java"
repositories {
jecenter()
}
}
}
gradle中,可以有很多project,可以定义project生成jar,生成war包,也可以创建project用于上传war文件。一个project又包含多个task。
task是一个操作,一个原子性操作。比如打个jar包,复制一分文件,编译一次Java代码
task xxxx{
doOne{
println 'hello'
}
}
task customTask1{
doFirst{
println "this is task"
}
doLast{
println "this is last"
}
}
task是一个关键字,它是project对象的一个函数,原型为create(String name,Closure configureClosure),customTask1是任务的名字;第二个参数是闭包,大括号里的代码。
tasks.create("customTask2"){
doFirst {
println "one"
}
doLast {
println "two"
}
}
dependsOn是Task类的一个方法,可以接收多个依赖的任务作为参数。
task hello {
println "hello"
}
task exMain (dependsOn:hello){
doLast {
println "main"
}
}
还可以依赖多个task
task exMain (){
dependsOn hello,world
doLast {
println "main"
}
}
project和Task 都可以让用户添加额外的自定义属性,使用ext
ext.name = 'lisi'
ext{
phone =890
address = 'hello'
}
task one{
println "$name"
println "$phone"
}
自定义属性还可以使用在sourceSet中,
sourceSets.all{
ext.resourceDir = null
}
sourceSets{
main{
resourcesDir ='/main'
}
test{
resourcesDir ="/test"
}
}
依赖于project给我们提供的快捷方法及TaskContainner提供的相关Create方法,可以有多种方式来创建任务。
def Task createTask = task(createTask)
createTask.doLast {
println "hello world"
}
createTask就是任务名字,可以使用.gradlew createTask 来执行这个任务。这种方式的创建其实调用project对象中的task(String name)的方法
第二种方式 以一个任务名字+ 一个对该任务配置的map对象来创建任务。
def Task createTask2 = task(createTask2,group: BasePlugin.BUILD_GROUP)
第三种:任务+闭包
task createTask3{
decription "演示"
doLast {
println "this is task + closure style"
}
}
我们创建的任务都会作为项目(project)的一个属性,属性名就是任务名,可以直接通过该任务名字访问和操作该任务;
其次,任务都是通过TaskContainer创建的,它是我们创建任务的集合,在project中我们通过tasks属性访问TaskContainer.访问的时候,任务名就是key
再则,通过路径访问,一个是get 一个是find,区别为get的时候如果找不到会抛出异常UnknowTaskException。而find找不到返回null。
通过名称访问,也有get 和find 两种,区别和上述一样。
任务分组就是分类,便于对任务进行归类整理。任务的描述就是说明这个任务有什么作用。
<< 操作符在gradle的task是doLast的短标记形式。
当我们执行一个Task的时候,其实就是执行其拥有的actions列表,这个列表保存在Task对象实例中的actions成员变量中,其类型是一个List
List<ContextAwareTaskAction> actions = new ArrayList<>()
我们把task之前执行、task本身执行、task之后执行分别称为doFirst 、doSelf、doLast
Task task = task two(type: CustomTask)
task.doFirst {
println '之前执行'
}
task.doLast {
println '之后执行'
}
class CustomTask extends DefaultTask {
@TaskAction
def doSelf() {
println 'task 自身执行'
}
}
通过shouldRunAfter和mustRunAfter这两个方法,可以控制一个任务应该或者一定在某个任务之后执行,你可以控制任务的执行顺序,而不是通过强依赖的方式。
taskB.shouldRunAfter(taskA) 表示taskB 应该在taskA执行之后执行,这里的应该不是必须,有可能任务顺序不能按照预期完成。而mustRunAfter(taskA) 表示严格执行。
Task中有个enable属性,用于启用和禁用任务。默认true,表示启用。
断言就是一个条件表达式,Task有一个onlyif方法,接受一个闭包作为参数。如果该闭包返回ture表示任务执行。否则跳过。
我们创建的任务都有TaskContainer进行管理,所以当我们访问任务的时候都是通过TaskContainner进行访问,而TaskContainner继承NamedDomainObjectCollection,所以任务规则其实就是NamedDomainObjectCollection的规则
1.添加任务到项目,测试,编译,打包
2.添加依赖配置
3.向现有的对象类型添加新的扩展属性,帮助我们优化构建,eg:android{} 就是
4.对项目进行约定修改,应用Java插件后,约定src/main/java目录下是源码存放位置,
二进制插件就是实现了org.gradle.api.Plugin接口的插件,有PluginId
apply plugin:'java'
'java’是Java插件的plugin Id,他是唯一的。
apply plugin:org.gradle.api.plugins.JavaPlugin
因为包是默认导入的,可以去除
apply plugin:JavaPlugin
二进制插件一般被打包到jar里独立发布
应用脚本插件就是把这个脚本加载进来,使用from,后跟一个脚本文件,额可以本地,可以网络。
可以把脚本文件,进行分块,分段整理,拆分成共用、职责分明的文件。然后使用apply from来引用
apply from:'version.gradle'
apply 其他用法
void apply(Map options);
void apply(Closure closure);
void apply(Action supper ObjectConfiguration> action);
第三方发布的作为jar的二进制插件,先在buildscript{}配置其classpath才能使用。
buidlscript{}块是构建项目之前,为项目进行前期准备和初始化相关配置依赖的地方。
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
}
}
apply plugin:'java'
Java插件会为你的工程添加有用的默认设置和约定,如源代码位置,单元测试代码位置,资源文件位置。遵循默认就好。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p80UUp57-1637833595185)(C:\Users\chents\Pictures\6-1.png)]
src/main/java 源代码
src/main/resources 资源
src/test/java 单元测试源代码
src/test/resources 单元测试资源
main和test 是Java插件内置的两个源代码集合,也可以自定义添加
sourceSets{
vip{
}
}
//这样就会新建vip/java vip/resources目录
默认情况不需要这种目录结构;如果你想改变:
sourceSets {
main {
java{
srcDir 'src/java'
}
resources {
srcDir 'src/resources'
}
}
}
1.要使用第三方依赖,第一个告诉gradle去哪找到这些依赖,使用什么类型的仓库
buildscript {
repositories {
google()
mavenCentral()
}
}
有了仓库,告诉gradle依赖什么
group
name
version
dependencies {
compile group:'com.android.tools.build',name:'gradle',version:'4.2.2'
//也可以写成下面形式
compile "com.android.tools.build:gradle:4.2.2"
}
compile:编译时依赖
testCompile 编译单元测试依赖,不会打包到apk里
name | 继承 | 任务 | msg |
---|---|---|---|
compile | compileJava | 编译时依赖 | |
runtime | compile | 运行时依赖 | |
archives | uploadArchives | 项目发布构建 |
gradle中,执行任何操作都是任务驱动。
build任务:编译源码,处理资源,打包jar 编译测试用例,处理测试资源,运行
clean 删除生产的文件
assemble 不执行单元测试,只会编译打包
check 执行单元测试
javadoc生产api文档
sourceSets源集,是Java插件描述管理代码及资源,一个Java源代码和资源文件的集合。sourceSets是一个SourceSetContainer,可以查阅api.
name
output.classesDir 编译后目录
output.resourcesDir 编译后资源目录
java Java源文件
java.srcDirs Java源文件所在目录
resources 资源文件
resources.srcDirs 资源文件所在目录
sourceCompatibility 编译Java源文件使用的Java版本
targetCompatibility 编译生成的类的Java版本
rootProject.name = "Gradle_demo"
include ':app1'
include ':app2'
project(':app1').projectDir = new File(rootDir,'/app1')
subproject
可以在project的gradle文件里让所有子项目应用插件
subproject{
apply plugin 'com.android.application'
}
如果你的项目是一个库工程,要发布jar给其他人使用,gradle提供了方便的配置发布的功能。发布到本地目录、maven库、Ivy库。
task pushlish(type:Jar)
artifacts {
archives pushlish
}
//发布你的打包文件 到本地
uploadArchives {
repositories {
flatDir {
name 'libs'
dirs "$projectDir/libs"
}
}
}
//发布你的打包文件 到maven仓库
uploadArchives {
repositories {
mavenDeployer {
repository(url: Mavens.SNAPSHOTS_URL) {
authentication(
userName: Mavens.SNAPSHOTS_USERNAME,
password: Mavens.SNAPSHOTS_PASSWORD
)
}
pom.project {
version '1.0-SNAPSHOT'
artifactId 'widgets'
groupId 'com.xxx.xx'
description 'upload AAR'
}
}
}
}
uploadArchives是一个upload Task,用于上传我们的构件。
app插件id: com.android.application
library插件id: com.android.library
test插件id: com.android.test
1.配置应用Android Gradle 插件
dependencies {
classpath "com.android.tools.build:gradle:4.2.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"
}
2.就可以在module使用了
apply plugin:' com.android.application'
android {
compileSdk 31
}
android{}是Android 插件提供的一个扩展类型。
android{}是Android 插件提供的一个扩展类型。对Android Gradle工程进行自定义的配置,实现是com.anroid.build.gradle.AppExtension.是project的一个扩展。可参阅API
compileSdkVerison 编译Android SDK的版本
buildToolsVersion Android构建工具的版本,eg:appt、dex工具
defaultConfig 默认配置,是一个ProductFlavor,他允许我们根据不同情况产生多个不同的apk。渠道打包
buildTypes 是一个NamedDomainObjectContainer类型,是域对象。类似sourceSet。包含release/debug等。我们还可以新增构建的类型。release就是一种buildTypes
minifyEnabled 是否混淆
proguardFiles 混淆的管理文件,哪些文件进行混淆
assemble
check
build
connectedCheck
deviceCheck
lint
install uninstall
clean
defaultConfig是一个ProductFlavor,
//
defaultConfig {
applicationId "com.example.gradle_demo"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
applicationId是ProductFlavor的一个属性,用于指定生成APP的包名,默认情况下为null。默认会从AndroidManifest.xml读取。
minSdkVersion是ProductFlavor的一个方法。指定最低支持的Android版本。
targetSdkVersion
testApplicationId 用于配置测试APP的包名
testinstrumentationRunner 用于配置单元测试用的Runner.默认使用android.test.InstrumentationTestRunner
signingConfig 配置默认签名信息,对生成的APP签名
一个APP只有在签名后,才能被发布、安装、使用。一般有debug和release两种模式。
signingConfigs {
debug {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
applicationIdSuffix
applicationIdSuffix是buildTypes的一个属性,配置基于applicaitonId的后缀。如applicationId为com.example.xx,我们指定applicationIdSuffix为.debug. 那么生成的debug apk的包名为com.example.xx.debug
debuggable
debuggable是buildTypes的一个属性,用于配置是否生成一个可供调试的apk。true或者false
jniDebuggable和debugable类似,配置是否可供调试Jni(C/C++)的apk
multiDexEnabled 用于配置buildTypes是否启动自动拆分多个dex的功能,当app方法总量超过65535个方法的时候使用。
shrinkResources 用于配置是否自动清理未使用的资源。默认为false
zipalign是Android为我们提供整理优化apk文件的工具,提高系统和应用的运行效率,更快地读写apk中的资源,降低内存使用。
defaultConfig {
zipalign true
}