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

Posted znapast

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android知识要点整理(21)----Gradle 之创建任务和插件相关的知识,希望对你有一定的参考价值。

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和插件的方法就讲完了。

以上是关于Android知识要点整理(21)----Gradle 之创建任务和插件的主要内容,如果未能解决你的问题,请参考以下文章

Android 知识要点整理(13)----网络连接

Android 知识要点整理(12)----Animation(动画)

Android知识要点整理----控制相机

Android 知识要点整理(13)----网络连接

Android 知识要点整理(12)----Animation(动画)

Android知识要点整理----文件分享