Android Gradle學(xué)習(xí)(四):Project詳解

每一個 build.gradle 腳本文件被 Gradle 加載解析后,都會對應(yīng)生成一個 Project 對象,在腳本中的配置方法其實都對應(yīng)著 Project 中的API,如果想詳細了解這些腳本的配置含義,有必要對 Project 類做些深入的剖析。

1. Project類圖

當構(gòu)建進程啟動后,Gradle基于build.gradle中的配置實例化org.gradle.api.Project類,先來看看 Project 類的主要結(jié)構(gòu)(節(jié)選部分常用):

Project 類圖

接下來我們通過一些實際的例子,由淺入深的來體會這些 API 的含義。

2. getter/setter屬性

File bd = getBuildDir()
println "buildDir = ${bd.getAbsolutePath()}"

//獲取Project的名字
String name = getName()
println "project name = $name"

//設(shè)置Project的描述信息
setDescription "這是一個測試案例"
String desc = getDescription()
println "project description = $desc"

//獲取Project的路徑
String path = getPath();
println "project path = $path"

class VersionInfo {
    String version
    boolean release

    VersionInfo(String v, boolean release) {
        version = v
        this.release = release
    }

    String toString() {
        return "V-${version}-${release ? 'release' : 'debug'}"
    }
}
//設(shè)置Project的版本號,參數(shù)可以是任何對象,gradle內(nèi)部會使用 toString() 方法返回的值
setVersion(new VersionInfo("1.0.0", true))
println("project version = ${getVersion()}")

//設(shè)置Project的分組
setGroup "TestGroup"
println("project group = ${getGroup()}")

直接執(zhí)行 gradle 命令,可以看到在配置階段輸出以下結(jié)果:

> Configure project :
rootDir = /Users/hjy/Desktop/gradle
buildDir = /Users/hjy/Desktop/testgradle/build
project name = gradle
project description = 這是一個測試案例
project path = :
project version = V-1.0.0-release
project group = TestGroup

2. 創(chuàng)建task

我們在 build.gradle 文件中定義 task 的方式,其實都對應(yīng)的是 Project 類中的 task() 方法,從 Project 類圖中的 task API 可以看到有多種不同的形式,前面介紹 task 的章節(jié)已經(jīng)介紹過了,這里就不贅述了。

3. 文件操作

3.1 通過mkdir創(chuàng)建目錄
File mkDir = mkdir("${buildDir}/test");
File mkDir2 = mkdir("${buildDir}/test2")
println "檢測目錄是否創(chuàng)建成功:${mkDir.exists()}, ${mkDir2.exists()}"
3.2 通過file、files 定位文件
//定位單個文件,參數(shù)可以是相對路徑、絕對路徑
File testDir = file("${buildDir}/test")
println "文件定位是否成功:${testDir.exists()}"

//文件集合,Gradle里用 FileCollection 來表示
FileCollection fileCollection = files("${buildDir}/test", "${buildDir}/test2")
println "-------對文件集合進行迭代--------"
fileCollection.each {File f ->
    println f.name
}
println "-------文件迭代結(jié)束-------"
//獲取文件列表
Set<File> set = fileCollection.getFiles()
println "文件集合里共有${set.size()}個文件"
3.3 通過fileTree創(chuàng)建文件樹

Gradle里用 ConfigurableFileTree 來表示文件樹,文件樹會返回某個目錄及其子目錄下所有的文件,不包含目錄。

//先在build目錄下創(chuàng)建3個txt文件
file("${buildDir}/t1.txt").createNewFile()
file("${buildDir}/test/t2.txt").createNewFile()
file("${buildDir}/t1.java").createNewFile()

//1.通過一個基準目錄創(chuàng)建文件樹,參數(shù)可以是相對目錄,也可以是絕對目錄,與file()方法一樣
println "通過基準目錄來創(chuàng)建文件樹"
ConfigurableFileTree fileTree1 = fileTree("build")
//添加包含規(guī)則
fileTree1.include "*.txt", "*/*.txt"
//添加排除規(guī)則
fileTree1.exclude "*.java"
fileTree1.each { f ->
    println f    
}

//2.通過閉包來創(chuàng)建文件樹
println "通過閉包來創(chuàng)建文件樹"
ConfigurableFileTree fileTree2 = fileTree("build") {
    include "*/*.txt", "*.java"
    exclude "*.txt"
}
fileTree2.each { f ->
    println f    
}

//3.通過map配置來創(chuàng)建文件樹,可配置的選項有:dir: ''、include: '[]、exclude: []、includes: []、excludes: []
println "通過Map來創(chuàng)建文件樹"
def fileTree3 = fileTree(dir: "build", includes: ["*/*.txt", "*.java"])
fileTree3 = fileTree(dir: "build", exclude: "*.java")
fileTree3.each { f ->
    println f    
}
3.4 復(fù)制文件

復(fù)制文件需要使用復(fù)制任務(wù)(Copy)來進行,它需要指定要復(fù)制的源文件和一個目標目錄,復(fù)制的規(guī)則都是定義在 CopySpec 接口里的,更詳細的說明可參見 API 文檔。

task testCopyFile(type: Copy) {
    //復(fù)制build目錄下的所有文件
    from "build"
    //復(fù)制單獨的某個文件
    from "test.java"
    //復(fù)制某個文件樹下的所有文件
    from fileTree("build")

    include "*.txt"
    include "*.java"
    exclude "t1.txt"
    //指定目標目錄
    into "outputs"

    //對復(fù)制的文件重命名:通過閉包來映射
    rename { fileName ->
        //增加 rename_ 前綴
        return fileName.endsWith(".java") ? "rename_" + fileName : fileName
    }

    //通過正則來映射文件名:abctest.java 會映射成 abchjy.java
    rename '(.*)test(.*)', '$1hjy$2'
}

3.5 刪除文件
//刪除 build 目錄下所有文件
delete("${buildDir}")

4. 多項目構(gòu)建

前面我們介紹的例子,都是單獨執(zhí)行某一個 build.gradle 文件。但是我們在 Android 應(yīng)用開發(fā)中,一個 Project 可以包含若干個 module ,這種就叫做多項目構(gòu)建。在 Android Studio 項目中,根目錄都有一個名叫 settings.gradle 的文件,然后每個 module 的根目錄中又有一個 build.gradle 文件,Gradle 就是通過 settings.gradle 來進行多項目構(gòu)建的。

4.1 通過 settings.gradle 引入子項目

1.先創(chuàng)建如下幾個目錄及文件:

多項目構(gòu)建

如圖所示,在項目根目錄創(chuàng)建一個 settings.gradle,在根目錄、app以及l(fā)ibrary目錄下也都創(chuàng)建一個 build.gradle 文件。

2.在 settings.gradle 里引入子項目

include ":app", ":library"

3.在 build.gradle 里增加測試代碼

//在根目錄 build.gradle 里增加
println "-----root file config-----"

//在 app/build.gradle 里增加
println "-----app config-----"

//在 library/build.gradle 里增加
println "-----library config-----"

4.在項目根目錄執(zhí)行命令 gradle -q,結(jié)果如下:

-----root file config-----
-----app config-----
-----library config-----

這是一個多項目構(gòu)建的簡單例子,可以看到結(jié)構(gòu)與我們的 Android 項目是類似的。Gradle 在運行時會讀取并解析 settings.gradle 文件,生成一個 Settings對象,然后從中讀取并解析子項目的 build.gradle 文件,然后為每個 build.gradle 文件生成一個 Project 對象,進而組裝一個多項目構(gòu)建出來。

Settings 里最核心的API就是 include 方法,通過該方法引入需要構(gòu)建的子項目。

include(projectPaths: String...)

這里我們?yōu)槊總€ build.gradle 文件生成了一個 Project 對象,跟總共3個 Project,根目錄的 Project 我們稱之為 root project,子目錄的 Project 我們稱之為 child project。

4.2 項目配置

在根項目里可以對子項目進行配置:

//通過path定位并獲取該 Project 對象
project(path: String): Project
//通過path定位一個Project,并進行配置
project(path: String, config: Closure): Project

//針對所有項目進行配置
allprojects(config: Closure)
//針對所有子項目進行配置
subprojects(config: Closure)

我們修改根目錄 build.gradle 文件如下:

println "-----root file config-----"

//配置 app 項目
project(":app") {
    ext {
        appParam = "test app"
    }
}

//配置所有的項目
allprojects {
    ext {
        allParam = "test all project"
    }   
}

//配置子項目
subprojects {
    ext {
        subParam = "test sub project"
    }
}

println "allParam = ${allParam}"

修改 app/build.gradle 文件如下:

println "-----app config-----"
println "appParam = ${appParam}"
println "allParam = ${allParam}"
println "subParam = ${subParam}"

修改 library/build.gradle 文件如下:

println "-----library config-----"
println "allParam = ${allParam}"
println "subParam = ${subParam}"

運行結(jié)果如下:

-----root file config-----
allParam = test all project
-----app config-----
appParam = test app
allParam = test all project
subParam = test sub project
-----library config-----
allParam = test all project
subParam = test sub project

5. 構(gòu)建腳本配置

5.1 buildscript

配置該 Project 的構(gòu)建腳本的 classpath,在 Andorid Studio 中的 root project 中可以看到:

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
    }
}
5.2 apply
apply(options: Map<String, ?>)

我們通過該方法使用插件或者是其他腳本,options里主要選項有:

  • from: 使用其他腳本,值可以為 Project.uri(Object) 支持的路徑
  • plugin:使用其他插件,值可以為插件id或者是插件的具體實現(xiàn)類

例如:

//使用插件,com.android.application 就是插件id
apply plugin: 'com.android.application'
//使用插件,MyPluginImpl 就是一個Plugin接口的實現(xiàn)類
apply plugin: MyPluginImpl

//引用其他gradle腳本,push.gradle就是另外一個gradle腳本文件
apply from: './push.gradle'

6. 屬性

6.1 Gradle屬性

在與 build.gradle 文件同級目錄下,定義一個名為 gradle.properties 文件,里面定義的鍵值對,可以在 Project 中直接訪問。

//gradle.properties里定義屬性值
company="hangzhouheima"
username="hjy"

在 build.gradle 文件里可以這樣直接訪問:

println "company = ${company}"
println "username = ${username}"
6.2 擴展屬性

還可以通過 ext 命名空間來定義屬性,我們稱之為擴展屬性。

ext {
  username = "hjy"
  age = 30
}

println username
println ext.age
println project.username
println project.ext.age

必須注意,默認的擴展屬性,只能定義在 ext 命名空間下面。對擴展屬性的訪問方式,以上幾種都支持。

系列文章

Android Gradle學(xué)習(xí)(一):Gradle基礎(chǔ)入門
Android Gradle學(xué)習(xí)(二):如何創(chuàng)建Task
Android Gradle學(xué)習(xí)(三):Task進階學(xué)習(xí)
Android Gradle學(xué)習(xí)(四):Project詳解
Android Gradle學(xué)習(xí)(五):Extension詳解
Android Gradle學(xué)習(xí)(六):NamedDomainObjectContainer詳解
Android Gradle學(xué)習(xí)(七):Gradle構(gòu)建生命周期
Android Gradle學(xué)習(xí)(八):統(tǒng)計Task執(zhí)行時長
Android Gradle學(xué)習(xí)(九):一些有用的小技巧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容