Gradle是干嘛的?
简单的讲,Gradle是基于Groovy的项目自动化构建工具,用来声明项目配置
具体一点,在开发过程中主要实现工程的管理,例如依赖,打包,部署,发布,各种渠道的差异管理,Gradle负责将这些行为以代码的方式描述出来以实现行为的复用
基本概念
projects , tasks and action:工程,任务,还有行为
一个项目至少要有一个工程,一个工程至少要有一个任务,一个任务由一些行为组成
结合实例来理解:
对于一个标准的AS项目而言,一个build.gradle对应一个project,action则相当于build.gradle中的一段段代码块
在工程构建的过程中,gradle会根据build.gradle中的配置信息生成相应的project和task
Project实质上是一系列task的集合,每一个task执行一些工作,比如编译类文件,解压缩文件,删除文件等等
怎么用?
构建
- 初始化阶段:首先会创建一个Project对象,然后执行build.gradle配置这个对象。如果一个工程中有多个module,那么意味着会有多个Project,也就需要多个build.gradle
- 配置阶段:配置脚本会被执行,执行的过程中,新的task会被创建并且配置给Project对象
- 执行阶段:配置阶段创建的task会被执行,执行的顺序取决于启动脚本时传入的参数和当前目录
task
task标示一个逻辑上的执行单元
举几个栗子:
- 重新编译工程,用到一个叫做build 的task
- 清理工程,用到一个叫clean 的task
...
具体有哪些task可已通过gradle tasks查看
自定义task
在build.gradle中定义
- 方式1:
task haha {
println "HAHA"
}
执行gradle haha,则会打印出haha
- 方式2:
task hello << {
println "hello,world"
}
<<
意思是给hello这个task添加一些action,其实就是调用了task的doLast方法,相当于以下:
task hello {
doLast{
println "hello,world"
}
}
目前build.gradle中存在haha和hello两个task,我们执行一下gradle看看结果:
ckc@ckc-PC:~/AopDemo$ ./gradlew
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=gasp
> Configure project :
HAHA
The Task.leftShift(Closure) method has been deprecated and is scheduled to be removed in Gradle 5.0. Please use Task.doLast(Action) instead.
at build_1wojgokbha0tm9swmixbdcemv.run(/home/ckc/AopDemo/build.gradle:33)
结果可知,只执行了haha的task
这里就有两个疑问:
1.并没有执行haha的task,他为什么执行了?
2.既然haha执行了hello为神马没有执行?
解释是,方式1的定义方式生成的task是在初始化阶段就会默认执行,而方式2是在执行阶段才会执行
简单的讲就是doLast起到的作用
- 方式3:
// 需要继承自DefaultTask
class HelloTask extends DefaultTask {
// @Optional 表示在配置该Task时,message是可选的。
@Optional
String message = 'I am 34sir'
// @TaskAction 表示该Task要执行的动作,即在调用该Task时,hello()方法将被执行
@TaskAction
def hello() {
println "$message"
}
@Override
void onlyIf(Spec<? super Task> onlyIfSpec) {
}
@Override
void setOnlyIf(Spec<? super Task> onlyIfSpec) {
}
@Override
Task doFirst(Action<? super Task> action) {
return null
}
@Override
Task doLast(Action<? super Task> action) {
return null
}
@Override
int compareTo(Task task) {
return 0
}
@Override
void setActions(List<Action<? super Task>> actions) {
}
}
// hello使用了默认的message值
task helloOne(type: HelloTask)
// 重新设置了message的值
task helloTwo(type: HelloTask) {
message = "你站在这别动,我去给你买橘子"
}
当前工程中定义
我们可以把task定义在buildSrc
module中:
在项目的根目录下新建一个名为buildSrc
文件夹(一定要这样命名),然后依次新建子目录src/main/groovy
,然后可以建自己的包名,这里以com.oil为例,依次新建子目录demo/gradle/task,然后在buildSrc根目录下新建build.gradle文件,此build.gradle中:
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
在demo/gradle/task目录下创建HelloTask.groovy文件,此文件中:
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
class HelloThreeTask extends DefaultTask {
@Optional
String message = 'I am 34sir'
@TaskAction
def hello() {
println "hello world $message"
}
}
查看buildSrc
下的目录:
使用此task:
build.gradle中:
task helloThree(type: HelloThreeTask) {
message = "hello three"
}
执行命令:gradle helloThree
查看运行结果:
> Task :app:helloThree
hello world hello three
自定义plugin
build.gradle中:
apply plugin: DateAndTimePlugin
dateAndTime {
timeFormat = 'HH:mm:ss.SSS'
dateFormat = 'MM/dd/yyyy'
}
// 每一个自定义的Plugin都需要实现Plugin<T>接口
class DateAndTimePlugin implements Plugin<Project> {
//该接口定义了一个apply()方法,在该方法中,我们可以操作Project,
//比如向其中加入Task,定义额外的Property等。
void apply(Project project) {
println "Current time"
project.extensions.create("dateAndTime", DateAndTimePluginExtension)
//每个Gradle的Project都维护了一个ExtenionContainer,
//我们可以通过project.extentions进行访问
//比如读取额外的Property和定义额外的Property等。
project.task('showTime') << {
println "Current time is " + new Date().format(project.dateAndTime.timeFormat)
}
project.tasks.create('showDate') << {
println "Current date is " + new Date().format(project.dateAndTime.dateFormat)
}
}
}
//向Project中定义了一个名为dateAndTime的extension
//并向其中加入了2个Property,分别为timeFormat和dateFormat
class DateAndTimePluginExtension {
String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"
String dateFormat = "yyyy-MM-dd"
}
执行gradle showTime
以及gradle showDate
查看结果:
> Task :app:showTime
Current time is 14:52:11.539
> Task :app:showDate
Current date is 02/08/2018
执行task
执行多个task
gradle task1 task2 [...]
简化执行
对于名字太长的task可以简化执行
例如上面的hello就可以这样执行:
gradle hell //能唯一标识出task的字符串即可
自动执行任务
不想在每次打包前执行各种自定义的任务,我们可以在build时自动执行任务:
afterEvaluate {
tasks.matching {
// 以process开头以ReleaseJavaRes或DebugJavaRes结尾的task
it.name.startsWith('process') && (it.name.endsWith('ReleaseJavaRes') || it.name.endsWith
('DebugJavaRes'))
}.each { task ->
task.dependsOn(chVer, chSo) // 任务依赖:执行task之前需要执行dependsOn指定的任务
}
}
type
task clean(type: Delete) {
delete rootProject.buildDir
}
以上这段task想必大家都见过,这里出现了一个新的概念:type
task的有很多中类型,此处的类型就是delete,任务是删除文件
常见的type
- Copy
将文件复制到目标目录,同时,也可以执行重命名和过滤文件操作
替换AndroidManifest文件:
task chVer(type: Copy) { // 指定Type为Copy任务
from "src/main/manifest/AndroidManifestCopy.xml" // 复制src/main/manifest/目录下的AndroidManifest.xml
into 'src/main' // 复制到指定目标目录
rename { String fileName -> //在复制时重命名文件
fileName = "AndroidManifest.xml" // 重命名
}
}
替换so文件:
task chSo(type: Copy) {
from "src/main/jniLibs/test" // 复制test文件夹下的所有so文件
into "src/main/jniLibs/armeabi-v7a" //复制到armeabi-v7a文件夹下
}
- Sync
与Copy任务类似,唯一的区别是当执行时会复制源文件到目标目录,目标目录中所有非复制文件将会被删除,除非指定Sync.preserve(org.gradle.api.Action)
task syncDependencies(type: Sync) {
from 'my/shared/dependencyDir'
into 'build/deps/compile'
}
// 你可以保护目标目录已经存在的文件。匹配的文件将不会被删除。
task sync(type: Sync) {
from 'source'
into 'dest'
preserve {
include 'extraDir/**'
include 'dir1/**'
exclude 'dir1/extra.txt'
}
}
- Zip
创建ZIP归档文件,默认压缩文件类型为zip
task zip(type: Zip) {
from 'src/dist'
into('libs')
}
网友评论