Android知识要点整理(21)----Gradle 之创建任务和插件

本文详细介绍了Gradle中的任务创建,包括不同方式创建任务及其执行阶段的区别,以及如何设置任务依赖。此外,还探讨了自定义任务实例,如从属性文件读取密码,并定制构建过程,如重命名APK和动态创建任务。最后,文章讲解了自定义插件的实现,包括创建、打包和应用到项目中的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.定义Tasks

先看创建Tasks的代码示例:

//方式1
task hello

//方式2
task hello {
    println 'Hello, world!'
}

//方式3
task hello << {
    println 'Hello, world!'
}

//方式4
task(hello) << {
println 'Hello, world!'
}

//方式5
task('hello') << {
println 'Hello, world!'
}

//方式6
tasks.create(name: 'hello') << {
println 'Hello, world!'
}

上面六种方式都创建了一个名为 hello的task.但是他们是有区别的,方式1是个空任务,它不会干任何事;方式2和方式3在代码上看就差一个双箭头,但是它们是有本质区别的;方式2中,打印“hello,world“字符串的语句会在执行任务之前运行,而方式3会在执行任务的时候打印出”hello,world”,也就是说**方式2中的语句实在configuration阶段执行的,方式3中语句则是在execution阶段执行的;方式4、5、6是方式3的不同表现形式,本质上是一样的。看如下代码执行的结果:

task hello << {
    println 'Execution'
}
hello {
    println 'Configuration'
}

执行结果如下:

$ gradlew hello
Configuration
:hello
Execution

再看一种比较复杂的定义Task的方式,这种方式使用了doFirst 和doLast 代码块,它可以控制代码执行的先后顺序:

task mindTheOrder {
    println 'Configuration'

    doFirst {
        println 'Not really first.'
    }

    doFirst {
        println 'First!'
    }

    doLast {
        println 'Not really last.'
    }

    doLast {
        println 'Last!'
    }
}

执行结果如下:

$ gradlew mindTheOrder
Configuration
:mindTheOrder
First!
Not really first.
Not really last.
Last!

2.Tasks之间的依赖

如果要决定tasks之间执行的先后顺序,我们可以有2种方式:
第一种 使用mustRunAfter 方法,示例代码如下:

task task1 << {
    println 'task1'
}
task task2 << {
    println 'task2'
}
//定义task2必须在task1之后执行
task2.mustRunAfter task1

看看执行命令的结果:

$ gradlew task2 task1
:task1
task1
:task2
task2

可以看出,虽然指定参数时task2在task1之前,但是task2实际是在task1执行完后才执行的。需要强调的是,task2并不需要task1必须有,如果没有指定task1,task2仍然会执行。

第二种方式就是使用 dependsOn方法。看示例:

task task1 << {
    println 'task1'
}

task task2 << {
    println 'task2'
}
task2.dependsOn task1

看看命令的执行结果:

$ gradlew task2
:task1
task1
:task2
task2

可以看出,虽然命令参数没有指定task1,但是执行时还是先执行了task1,再执行task2,task2的执行必须要有task1的执行。这个是dependsOn方法和mustRunAfter方法的主要区别。

3.Task实例

下面定义task用来获取签名密码。先创建一个属性文件private.properties.内容如下:

//定义密码
release.password = thepassword

然后定义一个task,用于从属性文件中读取密码。代码如下:

task getReleasePassword << {
    def password = ''
    if (rootProject.file('private.properties').exists()) {
        Properties properties = new Properties();
        //加载属性文件,得到一个属性对象
        properties.load( rootProject.file
                ('private.properties').newDataInputStream())
        //得到密码
        password = properties.getProperty('release.password')
    }

    //如果密码为空,则在命令行界面提示用户输入密码
    if (!password?.trim()) {
        password = new String(System.console().readPassword
            ("\nWhat's the secret password? "))
    }
    //将密码赋值给签名配置
    android.signingConfigs.release.storePassword = password
    android.signingConfigs.release.keyPassword = password
}

自此,完整的任务已经定义好了。下一步就是如何触发它的执行。方法如下:

//任务载入到gradle模型时会执行下面的方法
//方法通过添加依赖关系来触发上面定义的任务的执行
tasks.whenTaskAdded { theTask ->
    if (theTask.name.equals("packageRelease")) {
        theTask.dependsOn "getReleasePassword"
    }
}

4.定制构建过程

如何影响Android的构建过程,一种方式如下所示:

android.applicationVariants.all { variant ->
    // Do something
}

上述代码遍历APP所有的构建变体,我们可以针对特定的构建变体定义自己的逻辑。比如,重命名生成的apk文件。代码示例如下:

//针对libray,则需要使用libraryVariants对象
android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        def file = output.outputFile
        output.outputFile = new File(file.parent,
                file.name.replace(".apk", "-${variant.versionName}.apk"))
    }
}

再比如,动态创建task,示例如下:

android.applicationVariants.all { variant ->
    if (variant.install) {
        //为每个构建变体创建一个run任务
        //run任务依赖install任务
        tasks.create(name: "run${variant.name.capitalize()}",
            dependsOn: variant.install) {
                description "Installs the ${variant.description} and runs
                    the main launcher activity."
                //执行启动主Activity的命令  
                doFirst {
                    //先得到正确的位置信息
                    def classpath = variant.applicationId
                    if(variant.buildType.applicationIdSuffix) {
                    classpath -= "${variant.buildType.applicationIdSuffix}"
                    }
                    def launchClass =
                    "${variant.applicationId}/${classpath}.MainActivity"
                    exec {
                        executable = 'adb'
                        args = ['shell', 'am', 'start', '-n',
                        launchClass]
                    }
                }
            }
    }
}

5.自定义插件

插件可以看作是一些列task的集合。为了创建插件,我们需要实现Plugin接口。简单的插件代码示例如下:

class RunPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.android.applicationVariants.all { variant ->
            if (variant.install) {
                //这里可以定义一系列任务
                project.tasks.create(name:
                    "run${variant.name.capitalize()}",
                    dependsOn: variant.install) {
                    // 定义任务逻辑
                }
            }
        }
    }
}

定义好了插件,我们通过如下代码来应用到项目中:

apply plugin: RunPlugin

如果我们想将插件打包为jar文件,以便其他项目也可以使用,那我们需要创建一个Groovy 模块。和其他模块一样,需要有一个build.gradle文件。内容如下:

//需要应用groovy插件,表示这是一个groovy模块
apply plugin: 'groovy'

//添加gradle相关的依赖,因为定义插件需要用到gradle 相关的api
dependencies {
    compile gradleApi()
    compile localGroovy()
}

然后确保模块中有如下的目录结构:

plugin
└── src
    └── main
        ├── groovy
            │ └── com
                │ └── package
                    │ └── name
        └── resources
            └── META-INF
                └── gradle-plugins

然后我们可以在com/package/name目录下创建RunPlugin.groovy文件,这个文件就是插件代码文件。内容如下:

package com.gradleforandroid

import org.gradle.api.Project
import org.gradle.api.Plugin

class RunPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.android.applicationVariants.all { variant ->
            // Task code
        }
    }
}

同时,为了让Gradle能够发现这个插件,需要在META-INFO/gradle-plugins目录下创建一个独特的文件。这个文件的名称必须和插件的ID匹配,对于RunPlugin插件,文件名对应为com.gradleforandroid.run.properties,也就是package+插件名称(Run)。文件内容也很独特,它用于指定实现插件的类名,内容如下:

implementation-class=com.gradleforandroid.RunPlugin

然后我们就可以指定gradlew assemble命令来生成jar包了。
最后可以将jar包加入到任意项目,然后在项目的根目录的build.gradle文件中添加如下代码:

buildscript {
    repositories {
        flatDir { dirs 'build_libs' }
    }
    dependencies {
        //指定插件的类路径:包名+plugin
        classpath 'com.gradleforandroid:plugin'
    }
}

//最后就可以应用该插件了
apply plugin: com.gradleforandroid.RunPlugin

至此,定义task和插件的方法就讲完了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值