Gradle 腳本

轉載自:https://www.cnblogs.com/dasusu/p/9064481.html

 

前言

上一篇寫個批處理來幫忙幹活---遍歷&字符串處理中,我們已經學習如何寫批處理腳本來幫我們做一些簡單的重複性工作,本篇繼續來學習如何用 Gradle 寫腳本,讓它也來幫我們幹活

Gradle 腳本

需求場景跟上一篇一樣,只是需要腳本能夠幫我們遍歷某個目錄下的文件,然後分別針對每個文件執行 java 命令,再輸出新的命名格式的文件即可,因此腳本涉及的方面仍然是:文件夾的遍歷操作、字符串處理、執行 java 命令。下面開始學習吧:

1. 遍歷指定文件夾下的文件

1.1 files()

命令

files(file1, file2, file3, file4...) .each {file ->
    println file.name
}

解釋:files() 方法可以理解成一個集合,通過參數往集合中添加元素,只要能將需要遍歷的目錄下的所有文件都通過參數,傳給 files(),那麼就可以直接通過 .each 來遍歷集合中的每個元素,達到遍歷文件夾的目的

示例

完整示例.png

def dir = new File("C:\Users\suxq\Desktop\outputs")  
files(dir.listFiles()).each { file ->
    println file.name
}

gradle遍歷示例.png

解釋:可以結合 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 更簡單,只需要傳入目錄的路徑,即可對目錄下的文件進行遍歷

示例

完整示例.png

def outputs = file("C:\\Users\\suxq\\Desktop\\outputs")
fileTree(outputs).each { file ->
    println file.name
}

gradle遍歷示例.png

過濾:如果不想遍歷整個目錄,那麼 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" 只支持單行字符串,不支持多行,剩下的四種都支持多行字符串,如下圖
Groovy字符串代碼示例
控制檯輸出結果

斜槓我也很少見,常見的是帶有 ${} 的字符串,比如: println "blog's url: ${blogUrl}" 這是 groovy 的 GString 特性,支持字符串插值,有點了類似於變量引用的概念,但注意,在 '...''''...''' 單引號表示的字符串裏不支持 ${}。當然,如果你要使用 java 的方式,用 + 來拼接也可以。

3. 執行 java 等命令

在批處理腳本中直接寫要運行的命令,終端就會自動去執行,但在 gradle 腳本中,如果也需要執行一些命令行下的指令時,就需要藉助 Gradle 提供給我們接口。

3.1 “xxx".execute()

命令: "xxx".execute()

解釋: "xxx" 就是需要執行的命令,比如 svn --versiongit --versionjava -versioncmd dir 等等,直接將需要執行的命令用字符串表示後調用 .execute() 方法,這個命令就可以執行了。

切記: 雖然這種方式很簡單,但也很有多問題:

  • 首先第一個,你要執行的這條命令必須在你電腦裏配置了相關的環境變量,否則會報系統找不到指令的錯誤。
  • 第二點,這種方式下,有時看不到輸出的信息,比如 svn --version 可以在控制檯中看到相關信息輸出,但是 java -version 這條命令卻在控制檯中看不到,至於爲什麼,還沒搞懂,有清楚的還望指點一下。

示例

  • 電腦配置了相關的環境變量,控制檯可以看到相關信息

    println "svn --version".execute().text.trim()

    svn示例.png

    解釋:text.trim() 是可以獲取到命令執行之後的輸出結果,所以可以直接將命令的執行結果打印出來查看命令的執行情況,如果需要這方面的需求的話,不然只需 "svn --version".execute() 命令就會執行了。

  • 電腦配置了相關的環境變量,但控制檯卻看不到相關輸出信息

    println "java -version".execute().text.trim()

    java示例.png

    解釋:這點我也搞清楚,不懂爲什麼通過 text 就可以獲取到 svn 命令的執行結果,但就獲取不到 java 命令的執行結果。但,雖然控制檯看不到信息,命令還是有成功執行的,我們可以測試一下:

    def workDir = "C:\\users\\suxq\\desktop"
    "javac -d . A.java".execute([], new File(workDir))

    java示例1.png

    解釋:我在桌面放一個 A.java 文件,而通過 javac -d . A.java 命令可以在當前路徑下生成一個 A.calss 文件。所以,通過 "xxx".execute() 方式確實可以正確執行指定命令,但有時可能在控制檯看不到輸出信息,至於原因我不清楚。

    另外,execute() 這個方法可以接收兩個參數,第一個參數我也不清楚,第二個參數是可以指定命令執行的工作路徑,因爲我把 A.java 放在桌面,所以我需要指定這條命令的工作路徑是在桌面,不然的話,這條命令中的 A.java 就需要給出絕對路徑。

  • 電腦沒有配置相關環境變量,腳本執行報錯

    "git --version".execute()

    git命令示例.png

    解釋:我電腦沒有配置 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方式

  1. 新建 Gradle 腳本文件,如 sign.gradle,放在與你項目的 app 層級的 build.gradle 同級別即可
  2. 在 app 層級的 build.gradle 文件開頭添加:apply from: 'sign.gradle'
  3. 在你自己建的 gradle 腳本文件中編寫你的腳本代碼,注意你自定義的 task 最好指定一個 group
  4. 此時在 Android Studio 右側的 Gradle 面板中就可以找到你自行指定的 group 中的所有 task,點擊即可執行

as執行gradle腳本示例.png

如果你的 Gradle 腳本文件中的 task 不指定一個 group 的話,那麼在 Gradle 面板中就有的你找了

gradle 命令行方式

如果你電腦有配置好 Gradle 的環境變量,那麼你直接在終端中輸入命令:gradlew task名 即可,如上圖中有 sign, sign2 等四個 task,終端下輸入 gradlew sign2 就可以執行 sign2 的工作了。

如果電腦沒配置 Gradle 環境變量,那每個項目下都會有一個 Gradle 文件夾,它支持我們執行命令,所以你也可以在 Android Studio 的 Terminal 中直接執行命令即可,打開它的時候路徑默認爲項目根目錄的路徑,在這裏就可以執行 Gradle 的命令了。

命令行執行示例.png

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 同一個目錄內即可。

完整示例.png

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()
        }
    }
}

完整示例3.png

效果:完美,可以解放雙手,讓腳本幹活去吧~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章