Gradle内核本身提供的自动化构建功能十分有限,所有实际的功能都是通过插件的形势提供的,如编译Java代码的功能。通过插件可以:
1. 添加新的Tasks,比如JavaCompile Task
2. 在Gradle中添加新的对象,比如SourceSet对象,该对象用于添加一些约定的规则,像是Java源码放在src/main/java路径下
3. 扩展Gradle内核对象
4. 扩展其他插件的对象
一个工程需要首先apply Gradle插件,然后才能使用该插件。使用方法很简单,直接通过task名称执行这个task就行了。
可以直接在项目的构建脚本中添加逻辑,也可以通过插件的方式封装构建逻辑并应用。
相比于直接在项目的构建脚本中添加逻辑,通过apply插件的方式提供了更多的优点:
- 复用性强,可以把相似的逻辑通过插件的方式应用于多个工程
- 模块化的方式易于理解和管理
- 简化工程的构建脚本
下面来讲解通过插件的方式封装构建逻辑并使用的方式。
插件可以通过源码的方式使用,也可以打包成jar包使用。
一个Gradle插件打包了一系列的构建逻辑,可以应用在不同工程的构建中。可以使用不同的语言(Groovy,Java或Scala等)来编写一个Gradle插件,并编译成二进制文件使用。
插件代码可以放在不同的位置,如Build Script中,buildSrc文件夹下,或者放在一个单独的工程中。
放在Build Script中
好处是插件代码会被自动编译并添加到classPath中,无需其他操作就能使用了。缺点是该插件只能在当前构建脚本中使用,无法在脚本之外使用放在buildSrc文件夹(rootProjectDir/buildSrc/src/main/groovy)下
优点是Gradle会自动编译并且添加到classPath中,当前工程里的构建脚本都可以使用该插件,缺点是插件不能被其他工程使用。放在一个单独的工程中
可以打包成一个jar包在任何工程里使用。该jar包可以包含一个或多个plugin,或者包含几个tasks,或者两者都有。
实现一个plugin很简单,只需要实现Plugin接口:
public interface Plugin {
void apply(T var1);
}
使用Gradle插件需要两步,第一步解析(resolve)插件,第二步应用(apply)插件到一个工程上。
解析插件是说找到指定版本的插件jar包并添加到构建脚本的classpath中,这个步骤完成后,插件的API就能在构建脚本中调用。只有通过jar包方式提供的插件才需要解析的过程,而通过脚本提供的插件自动完成解析。
应用插件就是在工程构建脚本中调用插件的apply方法,并传入当前project作为参数,这样插件可以通过传入的project参数修改project配置。解析和应用通过plugin DSL语法可以一步完成:
// 应用Gradle内核plugin可以使用短名称:
plugins {
id 'java'
}
// 应用社区plugin必须使用全名:
plugins {
id "com.jfrog.bintray" version "0.4.1"
}
或者通过历史遗留方法分两步分别完成解析和应用:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1"
}
}
apply plugin: "com.jfrog.bintray"
构建脚本通过调用插件的apply方法来实例化一个插件对象,apply方法传入的参数就是当前的project对象。插件类可以通过这个project对象对project进行配置,比如添加一个task,下面的代码中插件在实例化时向project中添加了一个名为hello的task,该task会打印一句话:
apply plugin: GreetingPlugin
class GreetingPlugin implements Plugin {
void apply(Project project) {
project.task('hello') {
doLast {
println "Hello from the GreetingPlugin"
}
}
}
}
通过gradle -q命令可以执行添加的hello task:
> gradle -q hello
Hello from the GreetingPlugin
需要注意的是,如果是在根目录的Build Script中apply了一个插件,那所有子项目中都会生成一个该插件的实例,可以控制在某些子项目中应用该插件,而另一些子项目中不应用。
settings.gradle
include 'helloA'
include 'helloB'
include 'goodbyeC'
build.gradle
plugins {
id "org.gradle.sample.hello" version "1.0.0" apply false
id "org.gradle.sample.goodbye" version "1.0.0" apply false
}
subprojects { subproject ->
if (subproject.name.startsWith("hello")) {
apply plugin: 'org.gradle.sample.hello'
}
if (subproject.name.startsWith("goodbye")) {
apply plugin: 'org.gradle.sample.goodbye'
}
}
处理生命周期
在经历生命周期的不同阶段时,构建脚本会接受到不同的通知消息(Notification),可以捕获这些消息并做一些相应的处理。
whenTaskAdded:当一个task被添加的时候
tasks.whenTaskAdded { task ->
switch (task.name) {
case 'bfd':
task.dependsOn 'assembleDebug'
break;
case 'bfr':
setAllConfig(app_version, online, version_name)
task.dependsOn 'assembleRelease'
break;
}
}
task bfd << {}
whenReady:配置完成后
gradle.taskGraph.whenReady { taskGraph ->
if (taskGraph.hasTask(release)) {
version = '1.0'
} else {
version = '1.0-SNAPSHOT'
}
}
beforeTask/afterTask:task执行前后
gradle.taskGraph.afterTask { Task task, TaskState state ->
if (state.failure) {
println "FAILED"
} else {
println "done"
}
}
更详细的流程可以看下面的代码演示:
gradle.afterProject {project, projectState ->
println "afterProject $project"
}
allprojects {
afterEvaluate { project ->
println "afterEvaluate 1"
}
}
gradle.taskGraph.whenReady { taskGraph ->
println 'whenReady 2'
}
gradle.taskGraph.beforeTask { Task task ->
if (task.name.equals("SayHello")) {
println "beforeTask SayHello 3"
}
}
task SayHello {
println 'SayHello task 0'
doFirst {
println 'first 4'
}
doLast {
println 'last 5'
}
}
gradle.taskGraph.afterTask { Task task, TaskState state ->
if (task.name.equals("SayHello")) {
println "afterTask SayHello 6"
}
}
输出如下:
SayHello task 0
afterProject project ':app'
afterEvaluate 1
afterProject project ':plugindemolib'
whenReady 2
beforeTask SayHello 3
first 4
last 5
afterTask SayHello 6
如何在插件中修改project中某个task的依赖,比如使check task依赖我们自定义的插件CodeCheckPlugin?可以通过下面的方式实现:
public class CodeCheckPlugin implements Plugin {
void apply(Project project) {
project.task('checkCodeAndSendEmail') << {
println "Hello world"
}
project.tasks.whenTaskAdded{ theTask ->
if(theTask.name.equals("assembleDebug")){
theTask.dependsOn "helloTask"
}
}
}
}
这样在执行project的assembleDebug Task时,就会首先执行自定义的CodeCheckPlugin里面的checkCodeAndSendEmail,完成一些自定义的检查或逻辑。比如我们可以使checkCodeAndSendEmail依赖findBug Task,配合Gitlab和Jenkins,可以实现对提交代码的自动检查,并将检查结果发送邮件给相关开发人员。
参考:
http://blog.csdn.net/sbsujjbcy/article/details/50782830
https://docs.gradle.org/current/userguide/custom_plugins.html
http://blog.csdn.net/sbsujjbcy/article/details/50782830
https://neyoufan.github.io/2016/12/09/android/Jenkins-ci%E5%AE%B9%E5%99%A8%E5%8C%96%E5%9C%A8Android%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8%EF%BC%88%E5%85%AC%E4%BC%97%E5%8F%B7%E7%89%88%EF%BC%89/