Gradle 建構總覽

Android 應用程式通常會使用 Gradle 建構系統進行建構。在深入探討如何設定版本的詳細資訊之前,我們將探索版本背後的概念,讓您能全面瞭解系統。

什麼是建構?

建構系統會將原始碼轉換為可執行的應用程式。建構作業通常會涉及多個工具,用於分析、編譯、連結及封裝應用程式或程式庫。Gradle 會使用以工作為基礎的方法來整理及執行這些指令。

Tasks 會封裝指令,將輸入內容轉換為輸出內容。外掛程式可定義工作及其設定。將外掛程式套用至建構作業會註冊其工作,並使用其輸入和輸出內容將這些工作連接在一起。舉例來說,將 Android Gradle 外掛程式 (AGP) 套用至建構檔案,即可註冊建構 APK 或 Android 程式庫所需的所有工作。java-library 外掛程式可讓您從 Java 原始碼建構 jar。Kotlin 和其他語言也有類似的外掛程式,但其他外掛程式旨在擴充外掛程式。舉例來說,protobuf 外掛程式可為 AGP 或 java-library 等現有外掛程式新增 protobuf 支援。

Gradle 偏好慣例而非設定,因此外掛程式會提供良好的預設值,但您可以透過宣告式特定領域語言 (DSL) 進一步設定建構作業。DSL 的設計目的是讓您指定要建構的內容,而非建構方式。外掛程式中的邏輯會管理「如何」處理。您可以在專案 (和子專案) 中的多個建構檔案中指定該設定。

工作輸入內容可以是檔案和目錄,以及以 Java 類型 (整數、字串或自訂類別) 編碼的其他資訊。輸出內容只能是目錄或檔案,因為它們必須寫入磁碟。將工作輸出內容連接至另一個工作輸入內容,即可將工作連結在一起,讓其中一個工作必須在另一個工作之前執行。

雖然 Gradle 支援在建構檔案中編寫任意程式碼和工作宣告,但這可能會讓工具更難瞭解您的建構作業,也讓您更難維護。舉例來說,您可以為外掛程式中的程式碼編寫測試,但無法在建構檔案中編寫測試。相反地,您應將建構邏輯和工作宣告限制在外掛程式 (由您或其他人定義) 中,並宣告要在建構檔案中使用該邏輯的方式。

Gradle 建構作業執行時會發生什麼事?

Gradle 建構作業分為三個階段。每個階段都會執行您在建構檔案中定義的不同程式碼部分。

  • 初始化會判斷建構作業應納入哪些專案和子專案,並設定包含建構檔案和套用外掛程式的類別路徑。這個階段著重於設定檔,您可以在其中宣告要建構的專案,以及擷取外掛程式和程式庫的位置。
  • 設定會為每個專案註冊工作,並執行建構檔案,以套用使用者的建構規格。請務必瞭解,設定程式碼無法存取執行期間產生的資料或檔案。
  • 執行會執行應用程式的實際「建構」作業。設定檔的輸出內容是任務的有向非循環圖 (DAG),代表使用者要求的所有必要建構步驟 (在指令列上提供的任務,或在建構檔案中設為預設值)。這張圖表代表工作之間的關係,無論是工作宣告中明確指出,或是根據工作輸入和輸出內容,如果工作輸入內容是另一項工作的輸出內容,則必須在該工作之後執行。這個階段會依圖表中定義的順序執行過時的工作,如果工作輸入內容自上次執行後未變更,Gradle 就會略過該工作。

詳情請參閱 Gradle 建構生命週期

設定 DSL

Gradle 會使用特定領域語言 (DSL) 設定建構作業。這種宣告式方法著重於指定資料,而非編寫逐步 (命令式) 指示。您可以使用 Kotlin 或 Groovy 編寫建構檔案,但我們強烈建議您使用 Kotlin。

DSL 可讓所有人 (包括領域專家和程式設計師) 更輕鬆地為專案做出貢獻,定義一種小型語言,以更自然的方式呈現資料。Gradle 外掛程式可以擴充 DSL,以便設定任務所需的資料。

舉例來說,設定建構的 Android 部分可能會如下所示:

Kotlin

android {
    namespace = "com.example.app"
    compileSdk = 34
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk = 34
        // ...
    }
}

Groovy

android {
    namespace 'com.example.myapplication'
    compileSdk 34
    // ...

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 24
        // ...
    }
}

在幕後,DSL 程式碼類似於以下內容:

fun Project.android(configure: ApplicationExtension.() -> Unit) {
    ...
}

interface ApplicationExtension {
    var compileSdk: Int
    var namespace: String?

    val defaultConfig: DefaultConfig

    fun defaultConfig(configure: DefaultConfig.() -> Unit) {
        ...
    }
}

DSL 中的每個區塊都由函式表示,該函式會使用 lambda 進行設定,並使用同名屬性存取該函式。這樣一來,建構檔案中的程式碼就會更像資料規格。

外部依附元件

Maven 建構系統引入了依附元件規格、儲存空間和管理系統。程式庫會儲存在存放區 (伺服器或目錄) 中,中繼資料則包含版本資訊和對其他程式庫的依附元件。您可以指定要搜尋哪些存放區、要使用的依附元件版本,建構系統會在建構期間下載這些項目。

Maven 成果會透過群組名稱 (公司、開發人員等)、成果名稱 (程式庫名稱) 和成果版本來識別。通常會以 group:artifact:version 表示。

這種做法可大幅改善建構管理。您經常會聽到這類存放區稱為「Maven 存放區」,但這只是描述建構元素的封裝和發布方式。這些存放區和中繼資料已在多個建構系統中重複使用,包括 Gradle (Gradle 可發布至這些存放區)。公開存放區可供所有人使用,而公司存放區則可將內部依附元件保留在公司內部。

您也可以將專案模組化,轉換為子專案 (在 Android Studio 中也稱為「模組」),這些子專案也可用做依附元件。每個子專案都會產生輸出內容 (例如 JAR 檔案),供子專案或頂層專案使用。這麼做可以隔離需要重建的部分,並在應用程式中更妥善地分隔責任,進而縮短建構時間。

我們會在「新增建構依附元件」一文中,進一步說明如何指定依附元件。

建構變化版本

建立 Android 應用程式時,通常會建構多個變化版本。變化版本包含不同的程式碼,或使用不同的選項建構,並由建構類型和變種版本組成。

建構類型會變更宣告的建構選項。根據預設,AGP 會設定「發布」和「偵錯」建構類型,但您可以調整這些類型並新增更多類型 (例如用於階段或內部測試)。

偵錯版本不會對應用程式進行精簡或模糊處理,而是加快建構作業並保留所有符號。此外,偵錯版本也會將應用程式標示為「可偵錯」,並使用通用偵錯金鑰簽署應用程式,以及啟用裝置上已安裝應用程式檔案的存取權。這樣一來,您就能在執行應用程式時,探索檔案和資料庫中的已儲存資料。

發布版本會對應用程式進行最佳化,並使用發布金鑰簽署應用程式,以及保護已安裝的應用程式檔案。

您可以使用產品變種版本,變更應用程式的所含來源和依附元件變化版本。舉例來說,您可能想為應用程式建立「試用版」和「完整版」變種版本,或者「免費」和「付費」變種版本。您可以在「main」來源集目錄中編寫常用來源,並在以變種版本命名的來源集中覆寫或新增來源。

AGP 會針對每個建構類型和變種版本組合建立變化版本。如果您未定義變種版本,系統會根據建構類型為變化版本命名。如果您同時定義這兩個值,變化版本的名稱會是 <flavor><Buildtype>。舉例來說,如果建構類型為 releasedebug,變種版本為 demofull,AGP 會建立變化版本:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

後續步驟

您現在已瞭解建構概念,請查看專案中的 Android 建構結構