Android 應用程式通常是使用 Gradle 建構系統建構而成。在深入瞭解如何設定建構作業之前,我們先來探討建構作業背後的概念,讓您從整體角度認識這個系統。
什麼是建構?
建構系統會將原始碼轉換為可執行的應用程式。建構作業通常會用到多種工具,用來分析、編譯、連結及封裝應用程式或程式庫。Gradle 會以工作為基礎,整理及執行這些指令。
工作會封裝指令,將輸入內容轉換為輸出內容。外掛程式會定義工作及其設定。將外掛程式套用至建構作業時,系統會註冊外掛程式的工作,並使用輸入和輸出內容將這些工作連結在一起。舉例來說,將 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 { version = release(36) { minorApiLevel = 1 } } // ... defaultConfig { applicationId = "com.example.app" minSdk { version = release(23) } targetSdk { version = release(36) } // ... } }
Groovy
android { namespace = 'com.example.app' compileSdk { version = release(36) { minorApiLevel = 1 } } // ... defaultConfig { applicationId = 'com.example.app' minSdk { version = release(23) } targetSdk { version = release(36) } // ... } }
在幕後,DSL 程式碼類似於:
fun Project.android(configure: ApplicationExtension.() -> Unit) {
...
}
interface ApplicationExtension {
var namespace: String?
fun compileSdk(configure: CompileSdkSpec.() -> Unit) {
...
}
val defaultConfig: DefaultConfig
fun defaultConfig(configure: DefaultConfig.() -> Unit) {
...
}
}
DSL 中的每個區塊都以函式表示,該函式會採用 lambda 來設定區塊,並使用同名的屬性來存取區塊。這讓建構檔案中的程式碼更像是資料規格。
外部依附元件
Maven 建構系統導入了依附元件規格、儲存和管理系統。程式庫會儲存在存放區 (伺服器或目錄) 中,並包含版本和對其他程式庫的依附元件等中繼資料。您可以指定要搜尋的存放區、要使用的依附元件版本,以及建構系統在建構期間下載的項目。
Maven 構件會依據群組名稱 (公司、開發人員等)、構件名稱 (程式庫名稱) 和構件版本識別。這通常以 group:artifact:version 表示。
這種做法可大幅提升建構管理效率。您通常會聽到這類存放區稱為「Maven 存放區」,但這一切都與構件的封裝和發布方式有關。這些存放區和中繼資料已在多個建構系統中重複使用,包括 Gradle (Gradle 可以發布至這些存放區)。公開存放區可供所有人共用,公司存放區則可保留內部依附元件。
您也可以將專案模組化為子專案 (在 Android Studio 中也稱為「模組」),這些子專案也能做為依附元件。每個子專案都會產生輸出內容 (例如 JAR),可供子專案或頂層專案使用。這樣一來,您就能隔離需要重建的部分,並更妥善地劃分應用程式中的責任,進而縮短建構時間。
我們會在「新增建構依附元件」中,詳細說明如何指定依附元件。
建構變化版本
建立 Android 應用程式時,您通常會想建構多個變體。變種版本包含不同的程式碼,或以不同的選項建構而成,並由建構類型和變種版本組成。
建構類型會因宣告的建構選項而異。根據預設,AGP 會設定「發行」和「偵錯」建構類型,但您可以調整這些類型,並新增更多類型 (可能用於預先發布或內部測試)。
偵錯版本不會縮減或混淆處理應用程式,因此建構速度較快,且會保留所有符號。此外,偵錯版本會將應用程式標示為「可偵錯」,並使用一般偵錯金鑰簽署,方便您存取裝置上已安裝的應用程式檔案。這樣一來,您就能在執行應用程式時,探索檔案和資料庫中儲存的資料。
發布版本會最佳化應用程式、使用發布金鑰簽署,並保護已安裝的應用程式檔案。
使用產品變種版本,您可以變更應用程式的內含來源和依附元件變種版本。舉例來說,您可能想為應用程式建立「demo」和「full」變種版本,或是「free」和「paid」變種版本。您可以在「主要」來源集目錄中編寫通用來源,並在以變種版本命名的來源集中覆寫或新增來源。
AGP 會為建構類型和變種版本的每種組合建立變數。如果未定義變種版本,系統會以建構類型命名變數。如果同時定義兩者,變數會命名為 <flavor><Buildtype>。舉例來說,如果建構類型為 release 和 debug,而變種版本為 demo 和 full,AGP 會建立下列變種版本:
demoReleasedemoDebugfullReleasefullDebug
後續步驟
現在您已瞭解建構概念,請查看專案中的 Android 建構結構。