本打算用gradle尝试着去写一些脚本方便项目的构建和打包,但是在复习gradle的时候有了一些新的理解,对gradle的理解不敢说精通,但也更透彻了,可以说是现在终于会写gradle了,所以打算从新写一个系列的文章来做个总结。
之前也发布过一些关于gradle的文章
浅谈Gradle(一)
浅谈Gradle(二)与SourceSet
Gradle排除依赖模块的某个类
Gradle自定义插件实现自定义Task
不要急,我不是让你去看这些东西,我是觉得当我回头去看以前写的这些东西,真的就是弟弟,那都是看大量别人的文章之后总结写出的,那也是别人的东西,怎么说呢,学了之后还是一种似懂非懂的感觉。这次不一样,这次我是看这个来写的,绝对权威绝对官方 https://docs.gradle.org/current/dsl/index.html,因为他本来就是官方。
一. 浏览Gradle官方文档
看到有很多内容,因为不止有android用到gradle嘛,左边还有个目录,入门那些的我们就不管了,进阶的也不管了,毕竟看到这里的多多少少也是写过一些gradle代码的,这章我们主要看这两个
二. gradle构建的生命周期
先简单讲讲生命周期吧,一些简单的东西我就不讲很详细了,比如一个项目有settings.gradle、根目录的build.gradle和模块build.gradle这些,就不详细讲了。
看官网给出的介绍
看不懂没关系,至少我们能肯定的是构建过程有3个生命周期,Initialization、Configuration和Execution,我建议记住这3个单词,而不要总用中文的初始化、构建、执行去理解。官网下了还良心的给出了个Demo,告诉我们每个生命周期执行的阶段
我不会kotlin所以就只讲groovy,其实差不多的。
Initialization阶段会执行settings里面的代码,Configuration阶段会执行所有build.gradle里面的操作,无论是不是task,Execution阶段会执行action里面的操作 (不懂什么是task什么是action的也别急,这里先了解下,往后学就知道了)所以这个Demo下面的内容我们不看,学其它的东西再回来看就豁然开朗了。
三. Project
我们直接讲Project,我记得我刚学gradle的时候经常看到有人写文章说gradle最重要的是Project、task和action,其实这样说确实能让新人很容易上手,却同样也很容易误导别人。
但是从Project入手是不会有错的,真的了解Project是什么之后,你就真正的能看出gradle的架构,到时候task、action什么的就一目了然了。
在上面截图的地方点击进入DSL参考
进来后左边目录有什么 Build script blocks、Core types、 Publishing types、 Container types 之类的,内容很多,但是我们都不管,我们就看project,点击project
进来之后看到Project下面有些概念,英文不好的朋友可以翻译看看这些概念,但是还是要记住他们的单词。
1. project基本概念
(1)Lifecycle 生命周期
(2)Tasks 任务
(3)Dependencies 依赖
(4)Multi-project Builds 多项目构建
(5)Plugins 插件
(6)Properties 属性
(9)Methods 方法
2. 生命周期
生命周期是说,project在Initialization阶段被创建,我们经常在settings.gradle写比如
include ':app'
在Initialization阶段执行这行代码,创建app这个模块的project对象,那就是说一般来说,每个module对应一个project对象。准确来说是gradle根据settings.gradle去找对应module的build.gradle来创建project对象,也就是说project就是build.gradle。
所以project对象对应的代码在哪写,project在哪里创建,这些应该都很清楚了。
3. Methods 方法
task放到之后再写,我更倾向于单独拿一章出来写,其它的也应该分出来讲,要从浅入深,所以先讲Methods,因为它简单。
把project当成一个对象,那这个对象里面有方法就很容易理解吧,先看看一般AS生成的build.gradle是怎样的,也就是project一般是怎样的(我随便找个Demo里面的app模块的代码)
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
buildToolsVersion "27.0.0"
defaultConfig {
applicationId "com.tencent.tmgp.yybtestsdk"
minSdkVersion 14
targetSdkVersion 27
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar','*.aar'])
}
我们先不要看android {......}里面的内容,这是plugin(插件)的知识,过滤掉之后
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar','*.aar'])
}
是的,整个project里面只剩一个dependencies 方法,这里多嘴说一下,为什么说是方法。这个是一个闭包的写法,不知道的话建议先看看groovy语法中的闭包,一个参数的情况下是能省略括号的。
然后看看project中有什么方法,其实还挺多的
截图截不完,具体的可以看官网的API https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html
我们随便拿一个方法来说,比如说getName,获取project的名称
就这样写
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar','*.aar'])
}
println this.getName()
this就是指这个project嘛,代码会在Configuration生命周期中执行,打印
嗯,我这个Module的名称就叫app,看得不过瘾没关系,我们可以再演示调用多一点的方法
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar','*.aar'])
}
println this.getName()
println this.getPath()
println this.getRootDir()
println this.getVersion()
打印结果
而且也能在文档中找到默认生成的dependencies
看到了吧,传的参数是一个闭包(至于闭包里面写什么内容,那就要参照官网文档了)
再比如文档中还有个ant(Closure configureClosure)方法,那你就能这样写
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar','*.aar'])
}
ant{
...........
}
那是不是只能在build.gradle里面调用文档中的方法,当然不是,当然也可以自己定义方法
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar','*.aar'])
}
println this.getName()
println this.getPath()
println this.getRootDir()
println this.getVersion()
// 定义一个打印的方法
def myfuction(String msg){
println msg
}
myfuction("6666666")
看结果
上面演示的是在自己内部调用自己的project方法,那在别的project对象中调用该project的方法呢?怎么有点绕,就是一号project调用二号project的方法,要怎么操作。
(为了节省时间,我拿我一个项目来说,这种情况肯定是多模块的情况)
我们先理一下思路,要在一个project调用另一个project的方法要怎么做?当然是先拿到这个project对象,然后再调用它的方法。这时候我们API找到对project的操作(多说一句,看API最好看Javadoc)
比较分散,可能没截完全部,总之在这个API中肯定是能找到的,光看上面的这些方法就知道能拿到所有能获取到的Project,简单说几个
(1)比如getAllprojects(),返回当前的project和子project的集合(子project的意思是比如Moudule的project就是根目录project的子project)
(2)比如getParent()就是获取父project
(3)比如project(String path)就是根据path获取project,有的人会问我怎么懂path是什么,没关系,你可以在对应的project中调用getPath()打印,就知道这个project的path是什么了(一般都是:app)。
还有很多方法能获取到相对应的project。
假如我在名为test的project中调用:app的project
println "测试 "+project(":app").getRootDir()
获取:app的根目录的地址,这样就行了,看得出什么不。
project(":app").getRootDir() 和 this,getRootDir() 得到的结果是一样的,因为他们都是同一个根目录下。
4. Properties
文档中也有个Properties文档
截不完图,详细的可以看文档,比如属性中有个常用的属性name,可以直接在project中获取。
println "属性name "+name
如果我们直接设值的话呢
name = "mytest"
println this.getName()
会提示这个属性是只读的属性。
想看关于这些属性更详细的信息的话,可以在文档下面找到Property details
你会发现属性后面有个只读的提示,name属性也是,所以无法直接这样修改属性。
还有有个额外属性操作,就是ext关键字。
在A的project中定义
ext.testStr = "test 66666666666666"
在B的project中调用
println project(":app").ext.testStr
这里先简单了解下这些原有的属性就行,在讲到插件的时候会解释更多。
project就大概先提到这些吧,其它内容在讲到task、dependencies和plugin也会提到一些相关的内容,学了project的生命周期和一些属性、方法之后,对project相信也会有一定的了解。