文/咖枯(简书作者)
原文链接:http://www.jianshu.com/p/cd1a78dc8346

前言

我们的项目打包APK前需要根据业务需要更改AndroidManifest文件内容和替换so文件来生成不同的apk。这样就需要手动来做这些事情以实现对应的需求。

手动修改的弊端
1.因为改动地方比较多,所以很容易出错或出现遗漏。
2.改动需要时间,生产效率低下。
3.对于不熟悉业务的人来说,修改起来比较困惑。

那既然这样有没有一种方法,通过一些指令来完成这些既繁琐又容易出错的重复性手工作业呢,这就是今天要介绍的Gradle Task了。

Task介绍

一个Task代表一个构建工作的原子操作,例如编译calsses或者生成javadoc。
Gradle中,每一个待编译的工程都叫一个Project。每一个Project在构建的时候都包含一系列的Task。比如一个Android APK的编译可能包含:Java源码编译Task、资源编译Task、JNI编译Task、lint检查Task、打包生成APK的Task、签名Task等。插件本身就是包含了若干Task的。
如下就是一个task的简单例子:

task hello {println 'Hello world!'
}

在AS的Terminal窗口输入命令

xxx\xxx>gradlew hello

执行结果如下:

Hello world!                           BUILD SUCCESSFUL     Total time: 2.163 secs

更多用法

task myTask
task myTask { configure closure }  // closure是一个闭包
task myType << { task action }    // <<符号是doLast的缩写
task myTask(type: SomeType)   // SomeType可以指定任务类型,Gradle本身提供有Copy、Delete、Sync等
task myTask(type: SomeType) { configure closure }
  • 一个Task包含若干Action。所以,Task有doFirst和doLast两个函数,用于添加需要最先执行的Action和需要和需要最后执行的Action。Action就是一个闭包。闭包,英文叫Closure,是Groovy中非常重要的一个数据类型或者说一种概念。
  • Task创建的时候可以通过 type: SomeType 指定Type,Type其实就是告诉Gradle,这个新建的Task对象会从哪个基类Task派生。比如,Gradle本身提供了一些通用的Task,最常见的有Copy 任务。Copy是Gradle中的一个类。当我们:task myTask(type:Copy)的时候,创建的Task就是一个Copy Task。
  • 当我们使用 taskmyTask{ xxx}的时候,花括号就是一个closure。
  • 当我们使用taskmyTask << {xxx}的时候,我们创建了一个Task对象,同时把closure做为一个action加到这个Task的action队列中,并且告诉它“最后才执行这个closure”

Task的API文档:https://docs.gradle.org/current/dsl/org.gradle.api.Task.html

Type

Copy
将文件复制到目标目录。此任务在复制时也可以执行重命名和过滤文件操作。它实现了CopySpec接口,使用CopySpec.from()方法可以指定源文件,CopySpec.into()方法可以指定目标目录。
例子:

task copyDocs(type: Copy) {from 'src/main/doc'into 'build/target/doc'
}//这是个Ant filter
import org.apache.tools.ant.filters.ReplaceTokens//这是一个闭包
def dataContent = copySpec {from 'src/data'include '*.data'
}task initConfig(type: Copy) {from('src/main/config') {include '**/*.properties'include '**/*.xml'filter(ReplaceTokens, tokens: [version: '2.3.1'])}from('src/main/config') {exclude '**/*.properties', '**/*.xml'}from('src/main/languages') {rename 'EN_US_(.*)', '$1'}into 'build/target/config'exclude '**/*.bak'includeEmptyDirs = falsewith dataContent
}

Copy的API文档:https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html

使用Copy解决我们项目中的问题

替换AndroidManifest文件

task chVer(type: Copy) { // 指定Type为Copy任务from "src/main/manifest/AndroidManifestCopy.xml"  // 复制src/main/manifest/目录下的AndroidManifest.xmlinto '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文件夹下
}

这样每次打包APK前执行以上任务就可以自动替换文件啦!

问:那如果有多个任务需要执行是不是要执行多次任务呢?
答:可以通过多任务命令调用一次即可。

gradlew task1 task2 [...]

问:任务名太长不想输入这么多字怎么办?
答:可以采用简化操作,但是必须保证可以唯一区分出该任务的字符,如:

gradlew cV

问:那我不想每次打包前都输入命令怎么办?
答:可以每次build时自动执行自定义任务。

afterEvaluate {tasks.matching {// 以process开头以ReleaseJavaRes或DebugJavaRes结尾的taskit.name.startsWith('process') && (it.name.endsWith('ReleaseJavaRes') || it.name.endsWith('DebugJavaRes'))}.each { task ->task.dependsOn(chVer, chSo)  // 任务依赖:执行task之前需要执行dependsOn指定的任务}
}

完整的build.gradle代码:

apply plugin: 'com.android.application'android {compileSdkVersion 23buildToolsVersion "23.0.3"defaultConfig {applicationId "com.skr.voip"minSdkVersion 15targetSdkVersion 19}buildTypes {debug {minifyEnabled false}release {minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'}}
}dependencies {//    compile fileTree(dir: 'libs', include: ['*.jar'])compile 'com.android.support:support-v4:23.4.0'...}task chVer(type: Copy) {from "src/main/manifest/AndroidManifestCopy.xml"  // 复制src/main/manifest/目录下的AndroidManifest.xmlinto 'src/main'  // 复制到指定目标目录rename { String fileName -> //在复制时重命名文件fileName = "AndroidManifest.xml" // 重命名}}task chSo(type: Copy) {from "src/main/jniLibs/test"   // 复制test文件夹下的所有文件into "src/main/jniLibs/armeabi-v7a" //复制到armeabi-v7a文件夹下
}afterEvaluate {tasks.matching {// 以process开头以ReleaseJavaRes或DebugJavaRes结尾的taskit.name.startsWith('process') && (it.name.endsWith('ReleaseJavaRes') || it.name.endsWith('DebugJavaRes'))}.each { task ->task.dependsOn(chVer, chSo)  // 任务依赖:执行task之前需要执行dependsOn指定的任务}
}

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'}
}

Sync的API文档:https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Sync.html

Zip

创建ZIP归档文件,默认压缩文件类型为zip。
例子:

task zip(type: Zip) {from 'src/dist'into('libs')
}

Zip的API文档:https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Zip.html

更多Tpye可参考Task的API文档

自定义Task

上面介绍的都是Gradle默认提供的Task,而在有些时候,我们希望创建一些具有特定功能的Task,这时我们可以自己定义Task。

在Gradle中,我们有3种方法可以自定义Task。

(1)在build.gradle文件中定义
Gradle使用的是Groovy代码,所以在build.gradle文件中,我们便可以定义Task类。

// 需要继承自DefaultTask
class HelloWorldTask extends DefaultTask {// @Optional 表示在配置该Task时,message是可选的。@OptionalString message = 'I am kaku'// @TaskAction 表示该Task要执行的动作,即在调用该Task时,hello()方法将被执行@TaskActiondef hello(){println "hello world $message"}
}// hello使用了默认的message值
task hello(type:HelloWorldTask)// 重新设置了message的值
task helloOne(type:HelloWorldTask){message ="I am a android developer"
}

(2)在当前工程中定义
当项目中自定义Task类型比较多时,可以将自定义Task写在buildSrc项目中。
具体做法为:在项目的根目录下新建一个名为buildSrc文件夹,然后依次新建子目录src/main/groovy,然后可以建自己的包名,这里以demo.gradle.task为例,依次新建子目录demo/gradle/task,然后在buildSrc根目录下新建build.gradle文件,里面写入:

 apply plugin: 'groovy'dependencies {compile gradleApi()compile localGroovy()
}

接着在demo.gradle.task包下,创建HelloWorldTask.groovy文件,将(1)中的HelloWorldTask部分代码粘贴过来。

import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskActionclass HelloWorldTask extends DefaultTask {@OptionalString message = 'I am kaku'@TaskActiondef hello() {println "hello world $message"}
}

最终目录结构如下:

Paste_Image.png

(3)在单独的项目中定义
当自定义的Task需要能够提供给其他项目中使用时,可以通过声明依赖的方式引入Task。
具体做法为: 创建一个项目,将(2)中的buildSrc目录下的内容copy到新建项目中,然后将该项目生成的jar文件上传到repository中。
build.gradle如下:

apply plugin: 'groovy'
apply plugin: 'maven'
version = '1.0'
group = 'skr'
archivesBaseName = 'hellotask'repositories.mavenCentral()dependencies {compile gradleApi()compile localGroovy()
}uploadArchives {repositories.mavenDeployer {repository(url: 'file:../lib')}
}

执行 gradlew uploadArchives ,所生成的jar文件将被上传到上级目录的lib(../lib)文件夹中。

在使用该HelloWorldTask时,客户端的build.gradle文件需要做以下配置:

buildscript {repositories {maven {url 'file:../lib'}}dependencies {classpath group: 'skr', name: 'hellotask', version: '1.0'}
}task hello(type: HelloWorldTask)

自定义Plugin

与自定义Task相似,也是3种定义方式,只是代码不一样:

apply plugin: DateAndTimePlugindateAndTime {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) {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 Task使用就介绍完了,深入的请自行查阅相关API文档。

文/咖枯(简书作者)
原文链接:http://www.jianshu.com/p/cd1a78dc8346

Gradle Task的使用相关推荐

  1. 【错误记录】Flutter 应用运行卡在 Running Gradle task ‘assembleDebug‘... ( 配置阿里云 Maven 仓库镜像 )

    文章目录 一. 报错信息 二. 解决方案 1. 解决方案 1 2. 解决方案 2 一. 报错信息 运行 Flutter 应用 , 会一直卡在 Running Gradle task 'assemble ...

  2. Android studio gradle task list 不显示问题

    问题描述 新电脑安装android studio后,导入工程,各种配置都弄好变更好,出现了如下情况: 之前习惯的gradle task 不在列表中,好不习惯. 正常期望如下: 处理方法 快捷键Ctrl ...

  3. Android 跟踪 Gradle Task 执行

    https://blog.csdn.net/sk719887916/article/details/84191771 作者:Tamic Gradle 大家并不陌生,但我相信你会使用它配置一些依赖,编写 ...

  4. Android Gradle Task详解

    创建一个task 创建一个task很简单,直接使用task关键字来创建,最常见的形式是使用task + 名字 + Closure代码块.示例如下. task ms1 {println("== ...

  5. Gradle task

    本文来自网易云社区 作者:孙有军 1:gradle脚本是使用groovy语言写的(DSL),groovy中有一个重要的概念闭包(Closure),Closure是一段单独的代码块,它可以接收参数,返回 ...

  6. flutter打包解决 Running Gradle task ‘assembleRelease‘...死循环问题

    其实说到底就是国内访问google源太慢或者超时,所以两个方案 方案一:让自己能顺利访问google 懂得都懂 方案二:更换镜像地址,一共需要更换一下3个地方 1-更改 flutter/package ...

  7. Android Gradle 自定义Task 详解

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/76408024 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

  8. android自定义task,Android Gradle 自定义Task 详解

    一:Gradle 是什么 Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具. 它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于X ...

  9. 【Android 修炼手册】Gradle 篇 -- Android Gradle Plugin 主要 Task 分析

    上文回顾 上篇文章里讲了 android gradle plugin 的整体流程,引入插件以后生成了很多 Task,这篇文章就谈谈生成的这些 Task 都有什么用处,以及一些主要 Task 的实现 预 ...

最新文章

  1. Xen Server二安装xc及管理xen主机
  2. ios xmlrpc
  3. 企业网络推广专员浅析企业网络推广初期网站优化应重视的一些问题
  4. 【CSDN】图片居中与调整大小
  5. SAP Hybris安装包里自带的apache ant
  6. RabbitMQ+PHP 教程六(RPC)
  7. linux lnmp15 部署laravel项目
  8. fedora 33 topbar_31省区市新增确诊33例,天津新增本地确诊1例
  9. acrobat professional的安装版本
  10. 20210924 python 技术点
  11. 计算机控制系统的框图,计算机控制系统原理框图.doc
  12. excalidraw 使用中文手写体
  13. keil5安装教程及下载
  14. 怎么把video文件改成mp4_怎么把视频转换成MP4格式?这招教你轻松搞定!
  15. 连接数据库显示: Access denied for user ‘root‘@‘locahost‘(using password:YES)解决方式。
  16. 第四篇:UE4视角切换节点,Possess和Set View Target With Blend的区别
  17. 第6章---机器人系统仿真
  18. Matlab - Solidworks 机器人建模(4)—— 如何把SolidWorks模型导入到Matlab (Simscape模型)
  19. 清风数学建模笔记——Excel画图保姆级教学
  20. mysql数据库j电子课件,MYSQL数据库技术分享PPT演示课件

热门文章

  1. SpringBootAdmin超详细教程以及端点指标控制
  2. qq邮件如何设置html阅读,如何得知对方是否已阅读QQ邮件?
  3. hbuilderx安装教程_HBuilderX安装使用教程
  4. rockchip中的vop
  5. Windows 下编译 EXE 文件时把一个外部 txt 文件编译到 EXE 里面
  6. 计算机网络专题讲座,我院举行《计算机网络新技术》专题讲座
  7. AD元件库下载不了的用下面这个链接试试
  8. 2022年“科学探索奖”获奖者90%具有海外经历
  9. 高中计算机听课总结,信息技术听课心得.doc
  10. RK3399教程:wifi驱动调试技巧