建構設定

Android 建構系統會彙整應用程式資源和編譯原始碼,並封裝至 APK 或 Android App Bundles,供您測試、部署、簽署及發布。Android Studio 使用進階建構工具包 Gradle 來自動執行管理建構程序,可讓您定義彈性的自訂建構設定。每項建構設定都能定義其本身的程式碼和資源,同時也能重複使用應用程式所有版本通用的部分。Gradle 適用的 Android 外掛程式可與建構工具包搭配使用,提供專門用於建構及測試 Android 應用程式的處理程序和可調整設定。

Gradle 和 Android 外掛程式將獨立於 Android Studio 之外執行。也就是說,您可以在 Android Studio 內部、裝置上的指令列或未安裝 Android Studio 的裝置 (例如持續整合伺服器) 上,建構 Android 應用程式。如果您並非使用 Android Studio,則可以透過指令列來瞭解如何建構及執行應用程式。建構作業的輸出內容不會因為您透過指令列、遠端裝置,或 Android Studio 來建立專案而有所差異。

注意:由於 Gradle 和 Android 外掛程式是獨立於 Android Studio 之外執行,因此需要您另外更新建構工具。請參閱版本資訊,瞭解如何「更新 Gradle 和 Android 外掛程式」。

透過 Android 建構系統的靈活性,您無須修改應用程式的核心文件也能自訂建構設定。本節將帶您瞭解 Android 建構系統作業的方式,以及該系統能如何協助您自訂及自動執行多個建構設定。如果只想進一步瞭解如何部署應用程式,請參考透過 Android Studio 建構及執行。想立即使用 Android Studio 建立自訂建構設定,歡迎參考「設定建構變數」。

建構程序

建構程序牽涉到許多工具和程序的運作,相關工具和程序會將您的專案轉換為 Android 應用程式套件 (APK) 或 Android App Bundle (AAB)。因建構程序有很多的調整空間,若能瞭解實際運作情形將會有所幫助。

圖 1:典型 Android 應用程式模組的建構程序。

如圖 1 所示,典型 Android 應用程式模組的建構程序同以下次序:

  1. 編譯器會將原始碼轉換為 DEX (Dalvik Executable) 檔案,其中包括在 Android 裝置上執行的位元碼;此外,也會將其他內容轉換為已編譯資源。
  2. 視所選建構目標而定,分裝器會將 DEX 檔案和已編譯資源合併成 APK 或 AAB。APK 或 AAB 必須經過簽署,應用程式才能在 Android 裝置上安裝或發布至應用程式商店 (例如 Google Play)。
  3. 分裝器使用偵錯 KeyStore 或發布 KeyStore 來簽署 APK 或 AAB:
    1. 如果您打算建構僅用於測試和剖析的應用程式偵錯版本,分裝器會透過偵錯 KeyStore 來簽署您的應用程式。Android Studio 會自動使用偵錯 KeyStore 來設定新專案。
    2. 如果您打算建構對外發布的發布版本,分裝器必須使用經您設定過的發布 KeyStore 來簽署應用程式。如要建立發布 KeyStore,請參閱「在 Android Studio 中簽署應用程式」。
  4. 產生最終 APK 之前,分裝器會使用 zipalign 工具來最佳化您的應用程式,以減少在裝置上運作時的記憶體用量。

建構程序結束時,您就能取得應用程式的偵錯版或發布版 APK/AAB,其可用於部署、測試或向外部使用者發布。

Android Build 詞彙表

Gradle 和 Android 外掛程式可協助您設定下列部分的建構作業:

建構類型
建構類型可定義 Gradle 在建構及封裝應用程式時採用的特定屬性,通常是針對開發生命週期的不同階段進行設定。舉例來說,偵錯版本建構類型會啟用偵錯選項,並使用偵錯金鑰簽署應用程式;而發布版本建構類型可能會經過壓縮、混淆,並以發布金鑰簽署應用程式來以便未來發布。您必須定義至少一個建構類型,才能建構應用程式。根據預設,Android Studio 會建立偵錯和發布這兩種版本類型。如要開始為應用程式自訂封裝設定,請瞭解如何設定建構類型
變種版本
變種版本代表可向使用者發布的不同應用程式版本,例如免費版和付費版。您可運用不同的程式碼和資源來自訂變種版本,同時也能共用及重複使用所有應用程式版本之間通用的部分。您可以選擇是否提供變種版本,但您必須手動建立。在開始建立應用程式的不同版本之前,請參考設定變種版本
產品建構變數
建構變數是指建構類型和變種版本結合之後的產物,也是 Gradle 用於建構應用程式的設定。透過建構變數,您就能在開發期間建構變種版本的偵錯版本,或建構變種版本的已簽署發布版本,以供發布。雖然您無法直接設定建構變數,但可以對組成建構變數的建構類型和變種版本進行設定。建立其他建構類型或不同變種版本也會產生額外的產品建構變數。如要瞭解如何建立及管理建構變數,請參閱「設定建構變數」總覽。
資訊清單項目
您可以在設定產品建構變數時,指定資訊清單檔案中一部分屬性的數值。相關建構值會覆寫資訊清單檔案中原本的數值。如果您要為應用程式產生多種變化版本,配置不同的應用程式名稱、最低 SDK 版本或目標 SDK 版本,這項功能就能派上用場。當同時存在多個資訊清單時,Gradle 會合併資訊清單設定
依附元件
建構系統可管理來自本機檔案系統和遠端存放區的專案依附元件。這樣一來,您就不需要手動搜尋或下載依附元件的二進位套件,以及將套件複製到專案目錄中。詳情請參考新增建構依附元件
簽署
建構系統可讓您在建構設定中指定簽署設定,也能在建構程序期間自動簽署應用程式。建構系統會使用已知憑證透過預設金鑰和憑證來簽署偵錯版本,以免在建構期間收到要求輸入密碼的提示。除非您明確指定此建構作業的簽署方式,否則建構系統不會主動簽署發布版本。如果您還未發布金鑰,可按照「簽署應用程式」中的說明來產生金鑰。
程式碼和資源縮減
您可以透過建構系統為每個建構變數指定不同的 ProGuard 規則檔案。建構應用程式時,建構系統會採用適當的規則,並透過內建的縮減工具 (例如 R8) 縮減程式碼和資源
支援多個 APK
建構系統可讓您自動建立不同的 APK,讓每個 APK 只包含特定的螢幕密度或應用程式二進位檔介面 (ABI) 所需的程式碼和資源。詳情請參考建構多個 APK。請注意,我們建議採用發布單一 AAB 的方法,因為此方法可依據螢幕密度、ABI 和語言分割應用程式套件,同時降低將多個構件上傳至 Google Play 的複雜性。

建構設定檔

建立自訂建構設定時,您需要變更一或多個建構設定檔或 build.gradle 檔案。相關純文字檔用領域特定語言 (DSL) 來描述,並利用 Groovy 來操控建構邏輯。上述提及的 Groovy 是 Java 虛擬機器 (JVM) 的動態語言。不一定需要熟悉 Groovy 才能開始設定自己的版本,因為用於 Gradle 的 Android 外掛程式已包含大多數您需要的 DSL 元素。如要進一步瞭解 Android 外掛程式 DSL,請參閱DSL 參考文件

開始一項新的專案時,Android Studio 會自動為您建立一些檔案 (如圖 2 所示),並根據適當預設填入一些資訊。

圖 2:Android 應用程式模組的預設專案結構。

有些 Gradle 建構設定檔是 Android 應用程式標準專案結構的一部分。因此,在開始設定版本之前,請務必先瞭解相關檔案的適用範圍與目的,以及其所規定的 DSL 基本元素。

Gradle 設定檔

settings.gradle 檔案位於專案的根目錄中,可用於定義專案層級的存放區設定,並在建構應用程式時告知 Gradle 應納入哪些模組。在大多數的專案中,預設的檔案內容如下所示:

Groovy

pluginManagement {

    /**
     * The pluginManagement {repositories {...}} block configures the
     * repositories Gradle uses to search or download the Gradle plugins and
     * their transitive dependencies. Gradle pre-configures support for remote
     * repositories such as JCenter, Maven Central, and Ivy. You can also use
     * local repositories or define your own remote repositories. The code below
     * defines the Gradle Plugin Portal, Google's Maven repository,
     * and the Maven Central Repository as the repositories Gradle should use to look for its dependencies.
     */

    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {

    /**
     * The dependencyResolutionManagement { repositories {...}}
     * block is where you configure the repositories and dependencies used by
     * all modules in your project, such as libraries that you are using to
     * create your application. However, you should configure module-specific
     * dependencies in each module-level build.gradle file. For new projects,
     * Android Studio includes Google's Maven repository
     * and the Maven Central Repository by
     * default, but it does not configure any dependencies (unless you select a
     * template that requires some).
     */

    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "My Application"
include ‘:app’

Kotlin

pluginManagement {

    /**
     * The pluginManagement {repositories {...}} block configures the
     * repositories Gradle uses to search or download the Gradle plugins and
     * their transitive dependencies. Gradle pre-configures support for remote
     * repositories such as JCenter, Maven Central, and Ivy. You can also use
     * local repositories or define your own remote repositories. The code below
     * defines the Gradle Plugin Portal, Google's Maven repository,
     * and the Maven Central Repository as the repositories Gradle should use to look for its dependencies.
     */

    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {

    /**
     * The dependencyResolutionManagement { repositories {...}}
     * block is where you configure the repositories and dependencies used by
     * all modules in your project, such as libraries that you are using to
     * create your application. However, you should configure module-specific
     * dependencies in each module-level build.gradle file. For new projects,
     * Android Studio includes Google's Maven repository and the
     * Maven Central Repository by
     * default, but it does not configure any dependencies (unless you select a
     * template that requires some).
     */

    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "My Application"
include(":app")

多模組專案須指明應傳送至最終版本的所有模組。

頂層建構檔案

頂層 build.gradle 檔案位於專案的根目錄中,可明確定義適用於專案中所有模組的依附元件。根據預設,頂層建構檔案使用 plugins 區塊來定義專案中所有模組通用的 Gradle 依附元件。此外,頂層建構檔案也包含負責清除建構目錄的程式碼。建立新的專案之後,您可以在頂層 build.gradle 檔案中查看的預設設定和 DSL 元素如以下程式碼範例所示。

Groovy

plugins {

    /**
     * You should use `apply false` in the top-level build.gradle file
     * to add a Gradle plugin as a build dependency, but not apply it to the
     * current (root) project. You should not use `apply false` in sub-projects.
     * For more information, see
     * Applying external plugins with same version to subprojects.
     */

    id 'com.android.application' version '7.2.2' apply false
    id 'com.android.library' version '7.2.2' apply false
    id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Kotlin

plugins {

    /**
     * You should use `apply false` in the top-level build.gradle file
     * to add a Gradle plugin as a build dependency, but not apply it to the
     * current (root) project. You should not use `apply false` in sub-projects.
     * For more information, see
     * Applying external plugins with same version to subprojects.
     */

    id("com.android.application") version "7.1.0-beta02" apply false
    id("com.android.library") version "7.1.0-beta02" apply false
    id("org.jetbrains.kotlin.android") version "1.5.30" apply false
}

tasks.register("clean", Delete::class) {
    delete(rootProject.buildDir)
}

設定專案層級屬性

針對包含多個模組的 Android 專案,您可以在專案層級定義特定屬性,並與所有模組共用各該屬性。只要在頂層 build.gradle 檔案的 ext 資料塊中加入額外屬性即可。

Groovy

// This block encapsulates custom properties and makes them available to all
// modules in the project. The following are only a few examples of the types
// of properties you can define.
ext {
    sdkVersion = 28
    // You can also create properties to specify versions for dependencies.
    // Having consistent versions between modules can avoid conflicts with behavior.
    supportLibVersion = "28.0.0"
    ...
}
...

Kotlin

// This block encapsulates custom properties and makes them available to all
// modules in the project. The following are only a few examples of the types
// of properties you can define.
ext {
  extra["compileSdkVersion"] = 28
  // You can also create properties to specify versions for dependencies.
  // Having consistent versions between modules can avoid conflicts with behavior.
  extra["supportLibVersion"] = "28.0.0"
...
}
...

如要從相同專案中的模組存取各該屬性,請在模組的 build.gradle 檔案中使用以下語法 (以下章節將進一步說明此一檔案)。

Groovy

android {
    // Use the following syntax to access properties you defined at the project level:
    // rootProject.ext.property_name
    compileSdkVersion rootProject.ext.compileSdkVersion
    ...
}
...
dependencies {
    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
    ...
}

Kotlin

android {
    // Use the following syntax to access properties you defined at the project level:
    // rootProject.extra["property_name"]
    compileSdk = rootProject.extra["sdkVersion"]

    // Alternatively, you can access properties using a type safe delegate:
    val sdkVersion: Int by rootProject.extra
    ...
    compileSdk = sdkVersion
}
...
dependencies {
    implementation("com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}")
    ...
}

注意:雖然 Gradle 允許在模組層級中定義專案層級的屬性,但這會導致共用各該屬性的模組耦合,因此建議您避免執行這項操作。模組耦合將讓一個模組較難以獨立專案的方式匯出,並將明顯阻礙 Gradle 利用並列專案執行功能,以至於無法加快多個模組的建構作業。

模組層級建構檔案

模組層級 build.gradle 檔案位於各個 project/module/ 目錄中,可讓您對其所在的特定模組調整建構設定。調整相關建構設定會讓您得以提供自訂封裝選項,例如:額外的建構類型和變種版本,並可覆寫 main/ 應用程式資訊清單或頂層 build.gradle 檔案中的相關設定。

下列 Android 應用程式模組 build.gradle 檔案範例,大致列舉了一些您必須瞭解的基本 DSL 元素和設定。

Groovy

/**
 * The first line in the build configuration applies the Android plugin for
 * Gradle to this build and makes the android block available to specify
 * Android-specific build options.
 */

plugins {
  id 'com.android.application'
}

/**
 * The android block is where you configure all your Android-specific
 * build options.
 */

android {

    /**
     * The app's namespace. Used primarily to access app resources.
     */

    namespace 'com.example.myapp'

    /**
     * compileSdkVersion specifies the Android API level Gradle should use to
     * compile your app. This means your app can use the API features included in
     * this API level and lower.
     */

    compileSdkVersion 28

    /**
     * The defaultConfig block encapsulates default settings and entries for all
     * build variants, and can override some attributes in main/AndroidManifest.xml
     * dynamically from the build system. You can configure product flavors to override
     * these values for different versions of your app.
     */

    defaultConfig {

        // Uniquely identifies the package for publishing.
        applicationId 'com.example.myapp'

        // Defines the minimum API level required to run the app.
        minSdkVersion 15

        // Specifies the API level used to test the app.
        targetSdkVersion 28

        // Defines the version number of your app.
        versionCode 1

        // Defines a user-friendly version name for your app.
        versionName "1.0"
    }

    /**
     * The buildTypes block is where you can configure multiple build types.
     * By default, the build system defines two build types: debug and release. The
     * debug build type is not explicitly shown in the default build configuration,
     * but it includes debugging tools and is signed with the debug key. The release
     * build type applies Proguard settings and is not signed by default.
     */

    buildTypes {

        /**
         * By default, Android Studio configures the release build type to enable code
         * shrinking, using minifyEnabled, and specifies the default Proguard rules file.
         */

        release {
              minifyEnabled true // Enables code shrinking for the release build type.
              proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    /**
     * The productFlavors block is where you can configure multiple product flavors.
     * This allows you to create different versions of your app that can
     * override the defaultConfig block with their own settings. Product flavors
     * are optional, and the build system does not create them by default.
     *
     * This example creates a free and paid product flavor. Each product flavor
     * then specifies its own application ID, so that they can exist on the Google
     * Play Store, or an Android device, simultaneously.
     *
     * If you declare product flavors, you must also declare flavor dimensions
     * and assign each flavor to a flavor dimension.
     */

    flavorDimensions "tier"
    productFlavors {
        free {
            dimension "tier"
            applicationId 'com.example.myapp.free'
        }

        paid {
            dimension "tier"
            applicationId 'com.example.myapp.paid'
        }
    }
}

/**
 * The dependencies block in the module-level build configuration file
 * specifies dependencies required to build only the module itself.
 * To learn more, go to Add build dependencies.
 */

dependencies {
    implementation project(":lib")
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}

Kotlin

/**
 * The first section in the build configuration applies the Android plugin for
 * Gradle to this build and makes the android block available to specify
 * Android-specific build options.
 */

plugins {
    id("com.android.application")
}

/**
 * The android block is where you configure all your Android-specific
 * build options.
 */

android {

   /**
    * The app's namespace. Used primarily to access app resources.
    */

    namespace = "com.example.myapp"

    /**
     * compileSdkVersion specifies the Android API level Gradle should use to
     * compile your app. This means your app can use the API features included in
     * this API level and lower.
     */

    compileSdk = 28

    /**
     * buildToolsVersion specifies the version of the SDK build tools, command-line
     * utilities, and compiler that Gradle should use to build your app. You need to
     * download the build tools using the SDK Manager.
     *
     * This property is optional because the plugin uses a recommended version of
     * the build tools by default.
     */

    buildToolsVersion = "30.0.2"

    /**
     * The defaultConfig block encapsulates default settings and entries for all
     * build variants, and can override some attributes in main/AndroidManifest.xml
     * dynamically from the build system. You can configure product flavors to override
     * these values for different versions of your app.
     */

    defaultConfig {

        // Uniquely identifies the package for publishing.
        applicationId = "com.example.myapp"

        // Defines the minimum API level required to run the app.
        minSdk = 15

        // Specifies the API level used to test the app.
        targetSdk = 28

        // Defines the version number of your app.
        versionCode = 1

        // Defines a user-friendly version name for your app.
        versionName = "1.0"
    }

    /**
     * The buildTypes block is where you can configure multiple build types.
     * By default, the build system defines two build types: debug and release. The
     * debug build type is not explicitly shown in the default build configuration,
     * but it includes debugging tools and is signed with the debug key. The release
     * build type applies Proguard settings and is not signed by default.
     */

    buildTypes {

        /**
         * By default, Android Studio configures the release build type to enable code
         * shrinking, using minifyEnabled, and specifies the default Proguard rules file.
         */

        getByName("release") {
            isMinifyEnabled = true // Enables code shrinking for the release build type.
            proguardFiles(
                getDefaultProguardFile("proguard-android.txt"),
                "proguard-rules.pro"
            )
        }
    }

    /**
     * The productFlavors block is where you can configure multiple product flavors.
     * This allows you to create different versions of your app that can
     * override the defaultConfig block with their own settings. Product flavors
     * are optional, and the build system does not create them by default.
     *
     * This example creates a free and paid product flavor. Each product flavor
     * then specifies its own application ID, so that they can exist on the Google
     * Play Store, or an Android device, simultaneously.
     *
     * If you declare product flavors, you must also declare flavor dimensions
     * and assign each flavor to a flavor dimension.
     */

    flavorDimensions = "tier"
    productFlavors {
        create("free") {
            dimension = "tier"
            applicationId = "com.example.myapp.free"
        }

        create("paid") {
            dimension = "tier"
            applicationId = "com.example.myapp.paid"
        }
    }
}

/**
 * The dependencies block in the module-level build configuration file
 * specifies dependencies required to build only the module itself.
 * To learn more, go to Add build dependencies.
 */

dependencies {
    implementation(project(":lib"))
    implementation("com.android.support:appcompat-v7:28.0.0")
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
}

Gradle 屬性檔案

Gradle 也包含兩個位於專案根目錄中的屬性檔案,可用來指定 Gradle 建構工具包本身的設定:

gradle.properties
在此,您可以調整專案層級的 Gradle 設定,例如 Gradle Daemon 的最大堆積量。詳情請參閱「建構環境」。
local.properties
設定建構系統的本地環境屬性,包括:
  • ndk.dir - 到 NDK 的路徑。此一屬性已被淘汰。下載任何的 NDK 版本都會安裝在 Android SDK 目錄的 ndk 目錄中。
  • sdk.dir - 到 SDK 的路徑。
  • cmake.dir - 到 CMake 的路徑。
  • ndk.symlinkdir - 在 Android Studio 3.5 或以上版本中建立到 NDK 的符號連結,其路徑可能會比已安裝的 NDK 路徑還要短。

將 NDK 重新映射到較短的路徑 (僅限 Windows)

Windows 長路徑最常見的問題就是,已安裝 NDK 資料夾中的工具 (例如 ld.exe) 會產生過深的路徑,但這些工具本身無法有效支援長路徑。

local.properties 中,您可以將 ndk.symlinkdir 屬性設定為要求 Gradle 外掛程式建立指向 NDK 的符號連結。該符號連結的路徑可能會比現有 NDK 資料夾的路徑還短。舉例來說,ndk.symlinkdir = C:\ 能夠生成右側的符號連結:C:\ndk\19.0.5232133

將專案與 Gradle 檔案同步

變更專案中的建構設定檔時,Android Studio 會要求您同步專案檔案,以便套用您的建構設定變更;並請您試跑一些作業,確認您的設定不會發生建構錯誤。

如要同步專案檔案,請在進行變更後顯示的通知列中按一下 Sync Now (立即同步處理) (如圖 3 所示),或按一下選單列中的 Sync Project (同步處理專案) 圖示 。如果 Android Studio 發現您的設定有誤,例如原始碼使用了只能在 compileSdkVersion 以上的 API 層級中才會提供的 API 功能。這時,系統會顯示 Messages (訊息) 視窗並說明問題內容。

圖 3:在 Android Studio 中將專案與建構設定檔同步處理。

來源集

Android Studio 會按照邏輯將所有模組的原始碼和資源分為不同的來源集。模組的 main/ 來源集包含其所有建構變數使用的程式碼和資源。其他的來源集目錄可選擇性使用。因此,當您設定新的建構變數時,Android Studio 不會自動建立相關目錄。然而,建立類似於 main/ 的來源集有助於管理 Gradle 僅在建構特定應用程式版本時才會使用的檔案和資源:

src/main/
此來源集包含所有建構變數共用的程式碼和資源。
src/buildType/
建立此來源集,以便納入特定建構類型的程式碼和資源。
src/productFlavor/
建立此來源集,以便納入特定變種版本的程式碼和資源。

注意:如果您將建構設定調整為合併多個變種版本,則可以在不同版本維度之間為每個變種版本組合建立來源集目錄:src/productFlavor1ProductFlavor2/

src/productFlavorBuildType/
建立此來源集,以便納入特定建構變數的程式碼和資源。

舉例來說,如要產生應用程式的「fullDebug」版本,建構系統將會合併下列來源集的程式碼、設定和資源:

  • src/fullDebug/ (建構變數來源集)
  • src/debug/ (建構類型來源集)
  • src/full/ (變種版本來源集)
  • src/main/ (主要來源集)

注意:在 Android Studio 中新建檔案或目錄時 (依序點選 File (檔案) > New (新增) 選單項目),可針對特定的來源集進行建立。您可選擇的來源集取決於您的建構設定。如果所需的目錄不存在,Android Studio 就會自動建立。

當不同的來源集包含一個檔案的不同版本,Gradle 會以下列順序決定使用的檔案 (左側來源集會覆蓋右側來源集的檔案和設定):

建構變數 > 建構類型 > 變種版本 > 主要來源集 > 程式庫依附元件

這樣一來,Gradle 就能按照您要建立的建構變數選擇所要使用的檔案,同時重複使用與其他應用程式版本通用的活動、應用程式邏輯和資源。合併多個資訊清單時,Gradle 也會使用相同的優先順序。因此,各個建構變數都能在最終資訊清單中定義不同的元件或權限。如要進一步瞭解如何建立自訂來源集,請參閱「建立建構變數的來源集」。