写完批处理脚本,再写个Gradle脚本,解放双手
本篇文章已授权微信公众号 dasu_Android(大苏)独家发布
前言
上一篇写个批处理来帮忙干活---遍历&字符串处理中,我们已经学习如何写批处理脚本来帮我们做一些简单的重复性工作,本篇继续来学习如何用 Gradle 写脚本,让它也来帮我们干活
Gradle 脚本
需求场景跟上一篇一样,只是需要脚本能够帮我们遍历某个目录下的文件,然后分别针对每个文件执行 java 命令,再输出新的命名格式的文件即可,因此脚本涉及的方面仍然是:文件夹的遍历操作、字符串处理、执行 java 命令。下面开始学习吧:
1. 遍历指定文件夹下的文件
1.1 files()
命令:
files(file1, file2, file3, file4...) .each {file ->
println file.name
}
解释:files() 方法可以理解成一个集合,通过参数往集合中添加元素,只要能将需要遍历的目录下的所有文件都通过参数,传给 files(),那么就可以直接通过 .each 来遍历集合中的每个元素,达到遍历文件夹的目的
示例:
def dir = new File("C:\Users\suxq\Desktop\outputs")
files(dir.listFiles()).each { file ->
println file.name
}
解释:可以结合 File 的 listFiles() 方法使用,这个方法刚好可以返回整个目录下的文件,刚好作为参数传给 files(),这样一来就可以达到遍历文件夹的目的了。
过滤:如果只想遍历目录下符合规则的文件,那么可以自定义过滤规则:
def outputs = file("C:\\Users\\suxq\\Desktop\\outputs")
files(dir.listFiles(new FilenameFilter() {
@Override
boolean accept(File dir, String name) {
//自定义过滤规则
return name.endsWith(".apk")
}
}))
.each { file ->
println file.name
}
1.2 fileTree()
命令:
fileTree(dirPath).each { file ->
println file.name
}
解释:fileTree 使用会比 files 更简单,只需要传入目录的路径,即可对目录下的文件进行遍历
示例:
def outputs = file("C:\\Users\\suxq\\Desktop\\outputs")
fileTree(outputs).each { file ->
println file.name
}
过滤:如果不想遍历整个目录,那么 fileTree 方式也很容易自定义过滤规则:
def outputs = file("C:\\Users\\suxq\\Desktop\\outputs")
fileTree(outputs){
//自定义过滤规则
include "*.apk"
}
.each { file ->
println file.name
}
解释:fileTrss 的自定义过滤规则使用也很方便
注意:以上示例代码中,涉及到一些 groovy 语言的语法结构,Gradle 是基于 groovy 开发的,groovy 有一个闭包的概念,另外,groovy 支持方法的括号省略,方法的最后一个参数外移等特性,所以,如果上述代码看得不是很懂的话,可以到我之前写的一篇介绍 groovy 基础语法的博客看看:学点Groovy来理解build.gradle代码
1.3 java 实现
由于 Gradle 是基于 groovy 开发的,而 groovy 又是基于 java 开发的,因此,想要遍历指定目录下的文件,你也可以完全用 java 来实现,照样能在 Gradle 脚本中运行,java 实现的就不给示例了
2. 字符串处理
由于 Gradle 基于 groovy 开发,而 groovy 又是基于 java 开发的,因此,对字符串的处理完全可以使用 java 的方式,如通过 +
来拼接,或者通过 StringBuffer 对象来操作,或者直接使用 String 的 api 都可以。
所以,这一节就主要来讲讲,在 groovy 中可以表示为字符串的格式。
java 只支持用 "xxx"
双引号来表示字符串
groovy 支持使用 'xxx'
, "xxx"
, '''xxx'''
, """xxx"""
, /xxx/
, $/xxx/$
即单引号,双引号等6种方法来表示字符串
它们之间的区别为:'xxx'
, "xxx"
只支持单行字符串,不支持多行,剩下的四种都支持多行字符串,如下图
斜杠我也很少见,常见的是带有 ${}
的字符串,比如: println "blog's url: ${blogUrl}"
这是 groovy 的 GString 特性,支持字符串插值,有点了类似于变量引用的概念,但注意,在 '...'
, '''...'''
单引号表示的字符串里不支持 ${}
。当然,如果你要使用 java 的方式,用 +
来拼接也可以。
3. 执行 java 等命令
在批处理脚本中直接写要运行的命令,终端就会自动去执行,但在 gradle 脚本中,如果也需要执行一些命令行下的指令时,就需要借助 Gradle 提供给我们接口。
3.1 “xxx".execute()
命令: "xxx".execute()
解释: "xxx" 就是需要执行的命令,比如 svn --version
,git --version
,java -version
,cmd dir
等等,直接将需要执行的命令用字符串表示后调用 .execute()
方法,这个命令就可以执行了。
切记: 虽然这种方式很简单,但也很有多问题:
- 首先第一个,你要执行的这条命令必须在你电脑里配置了相关的环境变量,否则会报系统找不到指令的错误。
- 第二点,这种方式下,有时看不到输出的信息,比如
svn --version
可以在控制台中看到相关信息输出,但是java -version
这条命令却在控制台中看不到,至于为什么,还没搞懂,有清楚的还望指点一下。
示例:
电脑配置了相关的环境变量,控制台可以看到相关信息
println "svn --version".execute().text.trim()
解释:text.trim() 是可以获取到命令执行之后的输出结果,所以可以直接将命令的执行结果打印出来查看命令的执行情况,如果需要这方面的需求的话,不然只需 "svn --version".execute() 命令就会执行了。
电脑配置了相关的环境变量,但控制台却看不到相关输出信息
println "java -version".execute().text.trim()
解释:这点我也搞清楚,不懂为什么通过 text 就可以获取到 svn 命令的执行结果,但就获取不到 java 命令的执行结果。但,虽然控制台看不到信息,命令还是有成功执行的,我们可以测试一下:
def workDir = "C:\\users\\suxq\\desktop"
"javac -d . A.java".execute([], new File(workDir))
解释:我在桌面放一个 A.java 文件,而通过
javac -d . A.java
命令可以在当前路径下生成一个 A.calss 文件。所以,通过 "xxx".execute() 方式确实可以正确执行指定命令,但有时可能在控制台看不到输出信息,至于原因我不清楚。另外,execute() 这个方法可以接收两个参数,第一个参数我也不清楚,第二个参数是可以指定命令执行的工作路径,因为我把 A.java 放在桌面,所以我需要指定这条命令的工作路径是在桌面,不然的话,这条命令中的 A.java 就需要给出绝对路径。
电脑没有配置相关环境变量,脚本执行报错
"git --version".execute()
解释:我电脑没有配置 git 的环境变量,因此,通过这种方式来执行命令的时候是会报错的。
3.2 task xxx(type: Exec) {}
命令:task xxx(type: Exec) {}
解释:这种方式是官方给的教程里介绍的方式,官方链接跳转
示例:
task sign4(type:Exec) {
group = sign
//设置工作路径
workingDir 'C:\\Users\\suxq\\Desktop'
//执行 dir命令, /c 表示 cmd窗口执行完 dir 命令后立即关掉,至于 cmd 后可带哪些参数,可在终端下 cmd /? 查看
commandLine 'cmd', '/c', 'dir'
//执行 java -version 命令
//commandLine 'java', '-version'
//执行 svn --version 命令
//commandLine 'svn', '--version'
//执行 adb devices 命令
//commandLine 'cmd', '/c', 'adb devices'
}
解释:通过 Gradle 提供好的类型为 Exec 的 task,然后通过配置工作路径 workingDir, 需要执行的命令 commandLine,一个 Gradle 脚本就好了,然后通过 android studio 提供的 ui 界面执行或者 Gradle 的命令行形式直接执行这个 task 即可。
稍微介绍下上述一句话带过的 Gradle 脚本执行方式:
Android Studio方式:
- 新建 Gradle 脚本文件,如 sign.gradle,放在与你项目的 app 层级的 build.gradle 同级别即可
- 在 app 层级的 build.gradle 文件开头添加:apply from: 'sign.gradle'
- 在你自己建的 gradle 脚本文件中编写你的脚本代码,注意你自定义的 task 最好指定一个 group
- 此时在 Android Studio 右侧的 Gradle 面板中就可以找到你自行指定的 group 中的所有 task,点击即可执行
如果你的 Gradle 脚本文件中的 task 不指定一个 group 的话,那么在 Gradle 面板中就有的你找了
gradle 命令行方式:
如果你电脑有配置好 Gradle 的环境变量,那么你直接在终端中输入命令:gradlew task名
即可,如上图中有 sign, sign2 等四个 task,终端下输入 gradlew sign2
就可以执行 sign2 的工作了。
如果电脑没配置 Gradle 环境变量,那每个项目下都会有一个 Gradle 文件夹,它支持我们执行命令,所以你也可以在 Android Studio 的 Terminal 中直接执行命令即可,打开它的时候路径默认为项目根目录的路径,在这里就可以执行 Gradle 的命令了。
3.3 exec {}
命令:exec {}
解释:这个命令的用法可以说跟 3.2 介绍的方式一模一样,我个人针对这两个的区别理解就是,3.2 介绍的方式必须通过 task 方式去执行一个命令,但 exec{} 的方式可以通过方法也可以通过 task 方式,比较灵活,这是我的理解。
示例:
def sign() {
//设置命令执行结果的输出的地方
def out = new ByteArrayOutputStream()
//通过 exec {} 方式来执行命令
exec {
workingDir 'C:\\users\\suxq\\desktop'
commandLine 'cmd', '/c', 'dir'
//修改命令输出的地方,默认为控制台
standardOutput = out
}
//将命令的执行结果作为方法的返回值
return out
}
解释:def sign() 定义了一个方法,内部就可以通过 exec{} 来执行指定的命令,并且可以通过修改命令结果输出的地方来达到获取命令执行的结果的目的。而且,这个方法可以在你的 Gradle 脚本中在你需要的地方调用即可,而通常 task 之间只有前后依赖关系,而没有内部嵌套调用关系。
4. 完整示例
学习完上述内容后,知道了如何遍历操作,如何处理字符串,如何通过 Gradle 执行命令,就差不多可以来写 Gradle 脚本,让它帮我们做些事了,还是跟上一篇相同的场景:
场景:遍历指定路径目录下的所有 apk 文件,并通过一个 sign.jar 文件,分别对每个 apk 文件执行 java 命令来进行签名工作,sign.jar 接收两个参数,一个是需要签名的 apk,另外一个为输出的 apk,要求签名后的 apk 命名方式为将原文件名中的 unsign 替换成 google,并输出在跟 apk 同一个目录内即可。
apk 路径:c:\users\suxq\desktop\outputs
sign.jar 路径:c:\users\suxq\desktop
java 签名命令示例(要求 sign.jar 和 apk 文件都在同一路径下,即可用如下命令):
java -jar sign.jar meizi_1_3_0_debug_unsign.apk meizi_1_3_0_debug_google.apk
Gradle 脚本
task sign {
group = sign
doLast {
def signJar = "c:\\users\\suxq\\desktop\\sign.jar"
def apkPath = 'c:\\users\\suxq\\desktop\\outputs\\'
fileTree(file(apkPath)){
include "*.apk"
}
.each {file ->
def outApk = file.name.replace("unsign", "google")
//由于场景是模拟的,因此这里就只是将最后执行的java命令输出,从输出的命令中就可以看出命令是否可以正确执行
def java = "java -jar ${signJar} ${file.name} ${outApk}"
println java
//实际场景下,执行这句代码,上面代码只是为了看整合之后的命令
//"java -jar ${signJar} ${file.name} ${outApk}".execute()
}
}
}
效果:完美,可以解放双手,让脚本干活去吧~
最近(2018-03)刚开通了公众号,想激励自己坚持写作下去,初期主要分享原创的Android或Android-Tv方面的小知识,准备可能还有点不足,感兴趣的可以先点一波关注,谢谢支持~~
写完批处理脚本,再写个Gradle脚本,解放双手的更多相关文章
- 写个批处理脚本来帮忙干活--遍历文件夹&字符串处理
这次打算写几篇关于脚本方面的博客,主要是记录一下 Gradle 脚本和批处理脚本的一些写法,方便后续查阅. 前言 平常开发过程中,一些较为重复的手工性工作,如果能让脚本来帮忙处理,自然是最好的,刚好之 ...
- sass笔记-4|像写脚本一样写Sass,把能交给Sass办的都交给它
Sass笔记关于sass的基础部分已经写完,这一篇介绍Sass的高级特性--脚本特性.Sass能做很多事让样式表更智能,我们先会看到Sass眼中的数据类型,在这些数据类型上会有可进行的操作,此外,Sa ...
- 不写完不让回家的JQuery的事件与动画
在这看不见太阳的小黑屋里,苦逼的一天又开始了 好了闲话我也就不扯了,接下来我就来说说我对jQuery事件和动画的理解吧!!! 还是得再扯两句,我们敬爱的,Y老师讲完了,jQuery事件和动画,对着我们 ...
- Wiz写Blog? 不会再爱了,全面拥抱Markdown+Pandoc
Wiz写Blog? 不会再爱了,全面拥抱Markdown+Pandoc 文章转载自 http://iout.in/archives/454.html 我们为什么写作? 自从人们开始写作,写作便是记录. ...
- 用putty玩linux的时候由于以前用window 习惯写完东西按一下ctrl+s 保存
问题描述:用putty玩linux的时候由于以前用window 习惯写完东西按一下ctrl+s 保存,但是在putty一按下就不能再输入了.后来查找到:ctrl+s 是putty的一个命令大概是这样子 ...
- webstrom 在脚本区域写其他语言得到语法提示
webstrom 在脚本区域写其他语言得到语法提示 webstrom 的提示小灯泡 点击inject language or reference 选择相应的语言. 如果写的内容比较多, 可以按照web ...
- 再写一篇tps限流
再写一篇tps限流 各种限流算法的称呼 网上有很多文章介绍限流算法,但是对于这些算法的称呼与描述也是有点难以理解.不管那么多了.我先按我理解的维度梳理一下. 主要维度是:是正向计数还是反向计数.是定点 ...
- elasticsearch indices.recovery 流程分析(索引的_open操作也会触发recovery)——主分片recovery主要是从translog里恢复之前未写完的index,副分片recovery主要是从主分片copy segment和translog来进行恢复
摘自:https://www.easyice.cn/archives/231 elasticsearch indices.recovery 流程分析与速度优化 目录 [隐藏] 主分片恢复流程 副本分片 ...
- 【Java分享客栈】一个包装过简历的新同事写完微信支付引起事故后果断离职了
前言 挺长时间没发文了,因为公司有一个紧急项目要赶进度,加班如吃饭喝水,久违的进入到码农的状态. 之所以抽空来发个文,是这个项目才刚上线,时间不长却因为一位新同事的代码引起了生产环境的事故,造成了一批 ...
随机推荐
- 运行Myeclipse时,如何删除IVM窗口
windows------>preference------>run/debug------->lauching--------->percpectives,改成never,n ...
- Unity 数据Json格式的转换
把对象转换为字节序列的过程称为对象的序列化. 把字节序列化恢复为对象过程称为对象的反序列化. JSON格式的转换,是一大神给我说的,让我拿来存储数据库时对一些数据的处理,感觉特别好用.但是我并没有深入 ...
- Linux进程管理 - PRI,nice,free,uname,netstat
优先运行序 (priority, PRI) 这个 PRI 值越低代表越优先的意思.不过这个 PRI 值是由核心动态调整的, 使用者无法直接调整 PRI 值的. 由於 PRI 是核心动态调整的,我们使用 ...
- unity xml序列化与反序列化 多平台
换平台确实是一个头疼的问题,本来在pc用.net的json处理数据很是顺手的,但是发布web版本后,发现他不支持.后面找了好几个开源json都不能很好的支持web,或者不能支持List等.于是我就想着 ...
- 数据结构-C语言递归实现树的前中后序遍历
#include <stdio.h> #include <stdlib.h> typedef struct tree { int number ; struct tree *l ...
- ZeroMQ 教程 001 : 基本概览
介绍性的话我这里就不翻译了, 总结起来就是zmq很cool, 你应该尝试一下. 如何安装与使用zmq 在Linux和Mac OS上, 请通过随机附带的包管理软件, 或者home brew安装zmq. ...
- pandas数据处理基础——筛选指定行或者指定列的数据
pandas主要的两个数据结构是:series(相当于一行或一列数据机构)和DataFrame(相当于多行多列的一个表格数据机构). 本文为了方便理解会与excel或者sql操作行或列来进行联想类比 ...
- HTML5的canvas标签制作黑客帝国里的简单画面
1.加入canvas标签 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> ...
- getElementById 用法的一个技巧
假设实现把 TextBox1 的字符实时的拷贝到 TextBox2 中,代码如下: <Script language="Javascript"> fun ...
- Eclipse两种部署web项目方法
一).首先使用J2EE的Eclipse的Servers(可以从show view中取出). 1).通过Eclipse建立一个Dynamic Web Project 2).通过Servers视图来创建一 ...