新增建構依附元件

Android Studio 中的 Gradle 建構系統可以當做依附元件,輕鬆將外部二進位檔或其他程式庫模組加入建構作業中。依附元件可存放在本機或遠端存放區,且依附元件宣告的遞移依附元件也會自動加入。本頁面會說明如何在 Android 專案中使用依附元件,更將詳加闡述 Gradle 的 Android 外掛程式特定行為及設定。如需 Gradle 依附元件的相關概念指南,請一併參閱 Gradle 依附元件管理指南。提醒您,Android 專案只能使用本頁中定義的「依附元件設定」。

依附元件類型

如要為專案新增依附元件,請在模組 build.gradle.kts 檔案的 dependencies 區塊中指定 implementation 等依附元件設定。

舉例來說,下列應用程式模組的 build.gradle.kts 檔案包含三種不同的依附元件:

Kotlin

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

android { ... }

dependencies {
    // Dependency on a local library module
    implementation(project(":mylibrary"))

    // Dependency on local binaries
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))

    // Dependency on a remote binary
    implementation("com.example.android:app-magic:12.3")
}

Groovy

plugins {
    id 'com.android.application'
}

android { ... }

dependencies {
    // Dependency on a local library module
    implementation project(':mylibrary')

    // Dependency on local binaries
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // Dependency on a remote binary
    implementation 'com.example.android:app-magic:12.3'
}

這些要求各自具有不同的程式庫依附元件,如下所示:

本機程式庫模組依附元件

Kotlin

implementation(project(":mylibrary"))

Groovy

implementation project(':mylibrary')

此做法會宣告名為「mylibrary」的 Android 程式庫模組上的依附元件;此名稱必須符合您在 settings.gradle.kts 檔案中定義的程式庫名稱 include:。建構應用程式時,建構系統會編譯程式庫模組,並將產生的編譯內容封裝為應用程式。

本機二進位檔依附元件

Kotlin

  implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
  

Groovy

  implementation fileTree(dir: 'libs', include: ['*.jar'])
  

Gradle 宣告專案 module_name/libs/ 目錄中 JAR 檔案的依附元件 (因為 Gradle 會讀取相對於 build.gradle.kts 檔案的路徑)。

或者,您可以依照下列方式指定個別檔案:

Kotlin

  implementation(files("libs/foo.jar", "libs/bar.jar"))
  

Groovy

  implementation files('libs/foo.jar', 'libs/bar.jar')
  
遠端二進位檔依附元件

Kotlin

  implementation("com.example.android:app-magic:12.3")
  

Groovy

  implementation 'com.example.android:app-magic:12.3'
  

這項功能主要是:

Kotlin

  implementation(group = "com.example.android", name = "app-magic", version = "12.3")

Groovy

  implementation group: 'com.example.android', name: 'app-magic', version: '12.3'

可宣告「com.example.android」命名空間群組中的 12.3 版「app-magic」程式庫的依附元件。

注意:這類遠端依附元件會要求您宣告適當的遠端存放區,其中 Gradle 應搜尋程式庫。假如本機沒有相關程式庫,Gradle 會在建構作業需要遠端依附元件時 (例如當您點選「將專案與 Gradle 檔案同步處理」圖示 或執行建構作業時),從遠端網站提取這類元件。

如果您在編譯時間需要使用 AGP 依附元件,請務必將其加入明確依附元件。由於 AGP 在內部使用 api/implementation 設定,某些構件可能會從編譯的類別路徑中移除,而編譯的類別路徑可能會變更。

原生依附元件

自 Android Gradle 外掛程式 4.0 版本開始,原生依附元件也能匯入本頁面所述的手冊中。

根據會曝露原生程式庫的 AAR 而定,系統會自動將其提供給 externalNativeBuild 使用的建構系統。如要從程式碼存取程式庫,您必須在本頁面所述的原生建構指令碼中連結這些程式庫,請參閱使用原生依附元件

依附元件設定

dependencies 區塊內,您可以使用多種不同的依附元件設定 (例如上述的 implementation) 來宣告程式庫依附元件。每項依附元件設定都會為 Gradle 提供不同的依附元件使用方式說明。下表說明可在 Android 專案中依附元件的每項設定。下表也會將相關設定與 Android Gradle 外掛程式 3.0.0 版已淘汰的設定互相比較。

設定 行為
implementation Gradle 將依附元件新增至編譯的類別路徑,並將依附元件封裝到建構輸出內容。然而,當模組設定 implementation 依附元件時,Gradle 會知道您不想讓模組在編譯時將依附元件外洩到其他模組。也就是說,依附元件僅適用於其他執行階段的模組。

使用這項依附元件設定而非 apicompile (已淘汰) 可能會大幅改善建構時間,因為這樣可以減少建構系統需要重新編譯的模組數量。舉例來說,假使 implementation 依附元件變更其 API,Gradle 只會重新編譯依附元件,以及直接仰賴依附元件的模組。大多數的應用程式和測試模組都應使用這項設定。

api Gradle 會將依附元件新增至編譯的類別路徑,並建構輸出內容。當模組包含 api 依附元件時,Gradle 便會知道該模組想將依附元件直接傳輸至其他模組,以便在執行階段和編譯時間使用。

這種設定的運作方式與 compile (現已淘汰) 相同,但請務必謹慎使用,並只在您需要將資料連帶匯出至其他上游消費者的依附元件時使用。這是因為假使 api 依附元件變更其外部 API,Gradle 會在編譯時重新編譯可存取該依附元件的所有模組。因此,擁有多個 api 依附元件可能會大幅增加建構時間。除非您想將依附元件的 API 發布至其他模組,否則程式庫模組請改用 implementation 依附元件。

compileOnly Gradle 僅將依附元件新增至編譯類別路徑,不會將其新增至建構輸出內容。若您要建立 Android 模組,且在編譯期間需要用到依附元件,這項做法就很實用,但在執行階段中,您可自行選擇是否提供這項模組。

假使採用上述設定,程式庫模組必須包含執行階段條件,以便檢查依附元件是否可用,之後程式庫模組將妥善變更其行為,確保如未提供,服務仍可正常運作。如此便能避免新增不重要的暫時依附元件,進而縮減最終應用程式的大小。這項設定的運作方式與 provided (現已淘汰) 的運作方式相同。

注意:compileOnly 設定無法搭配 AAR 依附元件使用。

runtimeOnly Gradle 僅將依附元件新增至建構輸出內容,供執行階段使用,因此不會加入編譯類別路徑。這項設定的運作方式與 apk (現已淘汰) 的運作方式相同。
annotationProcessor

如要新增作為註解處理工具的程式庫的依附元件,您必須使用 annotationProcessor 設定,將依附元件新增至註解處理工具類別路徑,像這樣將編譯類別路徑與註解處理工具類別路徑分開,即可提升建構效能。如果 Gradle 發現編譯類別路徑上的註解處理工具,便會停用避免編譯的功能,對建構時間將造成負面影響 (Gradle 5.0 以上版本將忽略編譯類別路徑上的註解處理工具)。

假使 Android Gradle 外掛程式的 JAR 檔案包含下列檔案,就屬於註解處理工具:

META-INF/services/javax.annotation.processing.Processor

假使外掛程式偵測到編譯類別路徑上的註解處理工具,便會產生建構錯誤。

注意:Kotlin 專案應使用 kapt 宣告註解處理工具依附元件。

lintChecks

使用這項設定時,請納入您在建構專案時希望 Gradle 執行的 Lint 檢查作業。

注意:使用 Android Gradle 外掛程式 3.4.0 以上版本時,此依附元件設定不再將 Lint 檢查封裝到 Android 程式庫專案中。如要在 AAR 程式庫中加入 Lint 檢查依附元件,請使用以下所述的 lintPublish 設定。

lintPublish 在 Android 程式庫專案中使用這項設定,納入要讓 Gradle 編譯為 lint.jar 檔案並封裝 AAR 的 Lint 檢查項目。這會導致使用 AAR 的專案一併套用這些 Lint 檢查。假使您原先使用 lintChecks 依附元件設定在已發布的 AAR 中加入 Lint 檢查,則必須遷移這些依附元件,才能改用 lintPublish 設定。

Kotlin

dependencies {
  // Executes lint checks from the ":checks" project at build time.
  lintChecks(project(":checks"))
  // Compiles lint checks from the ":checks-to-publish" into a
  // lint.jar file and publishes it to your Android library.
  lintPublish(project(":checks-to-publish"))
}

Groovy

dependencies {
  // Executes lint checks from the ':checks' project at build time.
  lintChecks project(':checks')
  // Compiles lint checks from the ':checks-to-publish' into a
  // lint.jar file and publishes it to your Android library.
  lintPublish project(':checks-to-publish')
}
apk Gradle 僅將依附元件新增至建構輸出內容,供執行階段使用,因此不會加入編譯類別路徑。這項設定已淘汰 (適用於 AGP 1.0-4.2)。
compile Gradle 會將依附元件新增至編譯類別路徑並建構輸出,並將依附元件匯出至其他模組。這項設定已淘汰 (AGP 1.0-4.2 有提供)。
provided Gradle 僅將依附元件新增至編譯類別路徑 (也就是不會將其新增至建構輸出內容)。這項設定已淘汰 (AGP 1.0-4.2 有提供)。

上述設定會將依附元件套用至所有建構變數。假使您只想宣告特定建構變化版本來源集或測試來源集,您必須將設定名稱大寫,並加上建構變化版本或測試來源集的名稱做為其前置字串。

舉例來說,假使只想為「免費」產品口味新增 implementation 依附元件 (使用遠端二進位檔依附元件),看起來會像這樣:

Kotlin

dependencies {
    freeImplementation("com.google.firebase:firebase-ads:9.8.0")
}

Groovy

dependencies {
    freeImplementation 'com.google.firebase:firebase-ads:9.8.0'
}

然而,假使您想為合併變種版本建構類型的變數新增依附元件,就必須在 configurations 區塊中初始化設定名稱。以下範例會將 runtimeOnly 依附元件新增至「freeDebug」建構變數 (使用本機二進位檔依附元件)。

Kotlin

// Initializes a placeholder for the freeDebugRuntimeOnly dependency configuration.
val freeDebugRuntimeOnly by configurations.creating

dependencies {
    freeDebugRuntimeOnly(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
}

Groovy

configurations {
    // Initializes a placeholder for the freeDebugRuntimeOnly dependency configuration.
    freeDebugRuntimeOnly {}
}

dependencies {
    freeDebugRuntimeOnly fileTree(dir: 'libs', include: ['*.jar'])
}

如要為本機測試和檢測設備測試新增 implementation 依附元件,如下所示:

Kotlin

dependencies {
    // Adds a remote binary dependency only for local tests.
    testImplementation("junit:junit:4.12")

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}

Groovy

dependencies {
    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

然而,在這種情況下,部分設定並不合理。舉例來說,由於其他模組不能使用 androidTest,因此假使您使用 androidTestApi 設定,便會收到以下警示:

WARNING: Configuration 'androidTestApi' is obsolete and has been replaced with
'androidTestImplementation'.

新增註解處理工具

假使您將註解處理工具新增至編譯的類別路徑,便會看到與下列內容類似的錯誤訊息:

Error: Annotation processors must be explicitly declared now.

如要解決此問題,請透過 annotationProcessor 設定依附元件,以將註解處理工具新增至專案,如下所示:

Kotlin

dependencies {
    // Adds libraries defining annotations to only the compile classpath.
    compileOnly("com.google.dagger:dagger:version-number")
    // Adds the annotation processor dependency to the annotation processor classpath.
    annotationProcessor("com.google.dagger:dagger-compiler:version-number")
}

Groovy

dependencies {
    // Adds libraries defining annotations to only the compile classpath.
    compileOnly 'com.google.dagger:dagger:version-number'
    // Adds the annotation processor dependency to the annotation processor classpath.
    annotationProcessor 'com.google.dagger:dagger-compiler:version-number'
}

注意:Gradle 3.0.0 以上版本的 Android 外掛程式不再支援 android-apt 外掛程式

將引數傳遞至註解處理工具

假使您需要將引數傳遞給註解處理工具,請使用模組建構設定中的 AnnotationProcessorOptions 區塊。舉例來說,假使您想要將原始資料類型當做鍵/值組合傳遞,可以使用 argument 屬性,如下所示:

Kotlin

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments += mapOf("key1" to "value1",
                                   "key2" to "value2")
            }
        }
    }
}

Groovy

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                argument 'key1', 'value1'
                argument 'key2', 'value2'
            }
        }
    }
}

然而,使用 Android Gradle 外掛程式 3.2.0 以上版本時,您需要傳遞代表使用 Gradle CommandLineArgumentProvider 介面的檔案或目錄的處理工具引數。

使用 CommandLineArgumentProvider 即可讓您或註解處理工具作者透過對每個引數套用增量建構屬性類型註解,以改善遞增和快取清理建構的正確性與效能。

舉例來說,下列類別會實作 CommandLineArgumentProvider,並為處理工具的每個引數加上註解。

Kotlin

class MyArgsProvider(
    // Annotates each directory as either an input or output for the
    // annotation processor.
    @get:InputFiles
    // Using this annotation helps Gradle determine which part of the file path
    // should be considered during up-to-date checks.
    @get:PathSensitive(PathSensitivity.RELATIVE)
    val inputDir: FileCollection,

    @get:OutputDirectory
    val outputDir: File
) : CommandLineArgumentProvider {
    // Specifies each directory as a command line argument for the processor.
    // The Android plugin uses this method to pass the arguments to the
    // annotation processor.

    override fun asArguments(): Iterable<String> {
        // Use the form '-Akey[=value]' to pass your options to the Java compiler.
        return listOf("-AinputDir=${inputDir.singleFile.absolutePath}",
                      "-AoutputDir=${outputDir.absolutePath}")
    }
}

android {...}

Groovy

class MyArgsProvider implements CommandLineArgumentProvider {

    // Annotates each directory as either an input or output for the
    // annotation processor.
    @InputFiles
    // Using this annotation helps Gradle determine which part of the file path
    // should be considered during up-to-date checks.
    @PathSensitive(PathSensitivity.RELATIVE)
    FileCollection inputDir

    @OutputDirectory
    File outputDir

    // The class constructor sets the paths for the input and output directories.
    MyArgsProvider(FileCollection input, File output) {
        inputDir = input
        outputDir = output
    }

    // Specifies each directory as a command line argument for the processor.
    // The Android plugin uses this method to pass the arguments to the
    // annotation processor.
    @Override
    Iterable<String> asArguments() {
        // Use the form '-Akey[=value]' to pass your options to the Java compiler.
        ["-AinputDir=${inputDir.singleFile.absolutePath}",
         "-AoutputDir=${outputDir.absolutePath}"]
    }
}

android {...}

定義實作 CommandLineArgumentProvider 的類別後,您必須建立執行個體,並使用 annotationProcessorOptions.compilerArgumentProvider 方法將其傳送至 Android 外掛程式,如下所示。

Kotlin

// This is in your module's build.gradle file.
android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                // Creates a new MyArgsProvider object, specifies the input and
                // output paths for the constructor, and passes the object
                // to the Android plugin.
                compilerArgumentProvider(MyArgsProvider(files("input/path"),
                                                          file("output/path")))
            }
        }
    }
}

Groovy

// This is in your module's build.gradle file.
android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                // Creates a new MyArgsProvider object, specifies the input and
                // output paths for the constructor, and passes the object
                // to the Android plugin.
                compilerArgumentProvider new MyArgsProvider(files("input/path"),
                                         new File("output/path"))
            }
        }
    }
}

如要進一步瞭解如何實作 CommandLineArgumentProvider 來改善建構效能,請參閱「快取 Java 專案」。

停用註解處理工具錯誤檢查

假使您對包含不需要的註釋處理工具的編譯類別路徑有依附元件,可以透過將下列內容新增到 build.gradle.kts 檔案中來停用錯誤檢查功能。請注意,您新增至編譯類別路徑的註解處理工具尚未新增至處理工具類別路徑。

Kotlin

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                argument("includeCompileClasspath", "false")
            }
        }
    }
}

Groovy

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                includeCompileClasspath false
            }
        }
    }
}

假使您使用的是 Kotlin 和 kapt

Kotlin

android {
    ...
    defaultConfig {
        ...
        kapt {
            includeCompileClasspath = false
        }
    }
}

Groovy

android {
    ...
    defaultConfig {
        ...
        kapt {
            includeCompileClasspath false
        }
    }
}

如果在將專案的註解處理工具遷移至處理工具類別路徑後遇到問題,您可以將 includeCompileClasspath 設為 true,藉此允許編譯類別路徑上的註解處理工具。然而,我們不建議將此屬性設為 true,並且該選項將在 Android 外掛程式的未來更新中移除。

排除遞移依附元件

隨著應用程式的範圍擴大,可包含多種依附元件,包括直接依附元件和遞移依附元件 (應用程式匯入的程式庫所依附的程式庫)。如要不再需要排除遞移依附元件,您可以使用 exclude 關鍵字,如下所示:

Kotlin

dependencies {
    implementation("some-library") {
        exclude(group = "com.example.imgtools", module = "native")
    }
}

Groovy

dependencies {
    implementation('some-library') {
        exclude group: 'com.example.imgtools', module: 'native'
    }
}

從測試設定中排除遞移依附元件

假使您需要從測試中排除某些遞移依附元件,上述的程式碼範例可能無法正常運作。這是因為測試設定 (例如 androidTestImplementation) 會擴充模組的 implementation 設定。也就是說,Gradle 會在 Gradle 解析設定時一律包含 implementation 依附元件。

因此,如要從測試中排除遞移依附元件,您必須在執行時間執行,如下所示:

Kotlin

android.testVariants.all {
    compileConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
    runtimeConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
}

Groovy

android.testVariants.all { variant ->
    variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
    variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
}

注意:您仍然可以在依附元件區塊中使用 exclude 關鍵字,如「排除遞移依附元件部分中的原始代碼範例所示,以省略特定於測試設定且不包含在其他設定中的遞移依附元件。

設定 Wear OS 應用程式依附元件

設定 Wear OS 模組的依附元件時,做法與任何其他模組類似。也就是說,Wear OS 模組採用 implementationcompileOnly 等相同的依附元件設定。

Wear 模組也支援變化版本感知依附元件管理功能。因此,如果您的基本應用程式模組包含 Wear 模組中的依附元件,基本模組的每個變化版本都會使用 Wear 模組內的相符變化版本。

遠端存放區

假使您的依附元件不是本機程式庫或檔案樹狀結構,Gradle 會在 settings.gradle 檔案的 dependencyResolutionManagement { repositories {...} } 區塊中指定線上存放區中的檔案。所列存放區的順序決定 Gradle 針對各項專案依附元件搜尋存放區的順序。例如,假使存放區 A 和 B 都具有依附元件,而您在清單 A 中優先列出依附元件,Gradle 會從存放區 A 下載依附元件。

根據預設,新的 Android Studio 專案會指定 Google 的 Maven 存放區,並將 Maven 中央存放區指定為專案的 settings.gradle 檔案中的存放區位置,如下所示:

Kotlin


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

Groovy


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

如有需要的本機存放區,請使用 mavenLocal()

Kotlin


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        mavenLocal()
    }
}

Groovy


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        mavenLocal()
    }
}

或依照下列方式宣告特定的 Maven 或 Ivy 存放區:

Kotlin


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        maven(url = "https://repo.example.com/maven2")
        maven(url = "file://local/repo/")
        ivy(url = "https://repo.example.com/ivy")
    }
}

Groovy


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        maven {
            url 'https://repo.example.com/maven2'
        }
        maven {
            url 'file://local/repo/'
        }
        ivy {
            url 'https://repo.example.com/ivy'
        }
    }
}

詳情請參閱「Gradle 存放區指南」。

Google 的 Maven 存放區

您可以從 Google 的 Maven 存放區取得最新版的 Android 程式庫:

您可以在 Google 的 Maven 存放區索引找到所有可用的構件,詳情請參閱下方的「程式輔助存取機制」一節。

如要在您的建構中新增其中一個程式庫,請在頂層 build.gradle.kts 檔案中加入 Google 的 Maven 存放區:

Kotlin


dependencyResolutionManagement {

    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()

        // If you're using a version of Gradle lower than 4.1, you must instead use:
        // maven {
        //     url = "https://maven.google.com"
        // }
        // An alternative URL is "https://dl.google.com/dl/android/maven2/".
    }
}

Groovy


dependencyResolutionManagement {

    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()

        // If you're using a version of Gradle lower than 4.1, you must instead use:
        // maven {
        //     url 'https://maven.google.com'
        // }
        // An alternative URL is 'https://dl.google.com/dl/android/maven2/'.
    }
}

然後將所需程式庫新增至模組的 dependencies 區塊中。例如,appcompat 程式庫看起來會像這樣:

Kotlin


dependencies {
    implementation("com.android.support:appcompat-v7:28.0.0")
}

Groovy


dependencies {
    implementation 'androidx.appcompat:appcompat:1.6.1'
}

然而,假使您使用的是舊版程式庫,且依附元件無效,Maven 存放區就不會提供該程式庫,您必須從離線存放區取得程式庫。

程式輔助存取機制

如要透過程式輔助存取 Google Maven 構件,您可以從 maven.google.com/master-index.xml 取得 XML 構件群組清單。然後,您可以在任何群組中檢視下列程式庫名稱和版本:

maven.google.com/group_path/group-index.xml

舉例來說,android.arch.lifecycle 群組中的程式庫會列在 maven.google.com/android/arch/lifecycle/group-index.xml

您也可以透過下列方式下載 POM 和 JAR 檔案:

maven.google.com/group_path/library/version /library-versionext

例如:maven.google.com/android/arch/lifecycle/compiler/1.0.0/compiler-1。0.0.pom

來自 SDK Manager 的離線存放區

假使程式庫不適用於 Google Maven 存放區 (通常是較舊的程式庫版本),就必須從 SDK Manager 下載離線的 Google 存放區套件。

然後照常將這些程式庫加入 dependencies 區塊。

離線程式庫會儲存在 android_sdk/extras/ 中。

具有 Android Gradle 外掛程式的原生依附元件

AAR 程式庫可能包含 Android Gradle 外掛程式可使用的原生依附元件。AGP 也能產生 AAR,藉此向消費者顯示原生程式庫。

使用原生依附元件

從 Android Gradle 外掛程式 4.0 開始,C/C++ 依附元件可以從 build.gradle 檔案中的已連結 AAR 匯入。Gradle 會自動提供這些功能給原生建構系統,但您必須將建構系統設定為使用匯入的程式庫和標頭。由於 C/C++ 依附元件是以 AAR 發布,以下通用 AAR 的連結可能有所幫助:

  • 建立 Android 程式庫以取得一般 AAR 文件,以及如何將其整合至專案中,特別是當您打算將 AAR 當做本機 C/C++ 依附元件使用時。
  • 新增建構依附元件,瞭解如何在 build.gradle 檔案中新增依附元件 (特別是遠端依附元件)。

本文件說明如何設定原生建構系統,並假設您已將 C/C++ 依附元件 AAR 新增至專案的 Gradle 建構環境。

AAR 中的原生依附元件

Gradle 模組的 AAR 依附元件可能會曝露原生資料庫,以供應用程式使用。在 AAR 中,prefab 目錄包含 Prefab 套件,其中包含原生依附元件的標頭和程式庫。

每個依附元件最多可曝露一個 Prefab 套件,其中可含有一或多個模組。Prefab 模組是單一程式庫,可以是共用、靜態或僅限標頭的程式庫。

使用程式庫和模組名稱時,您需要知道程式庫的使用方式。依照慣例,套件名稱會與 Maven 構件名稱相符,而模組名稱會與 C/C++ 程式庫名稱相符,但並非必要。請參閱依附元件的說明文件,以判斷使用的名稱。

建構系統設定

您必須為 Android Gradle 模組啟用 prefab 功能。

如要這麼做,請將以下內容新增至模組 build.gradle 檔案的 android 區塊中:

Kotlin

buildFeatures {
  prefab = true
}

Groovy

buildFeatures {
  prefab true
}

您也可以在專案的 gradle.properties 檔案中設定版本

android.prefabVersion=2.0.0

一般來說,所選的預設 AGP 能符合您的需求。除非您需要修正錯誤或想使用的新功能,否則應選取其他版本。

從 AAR 匯入的依附元件會透過 CC_FIND_ROOT_PATH 曝露給 CMake。叫用 CMake 時,Gradle 會自動設定此內容值,所以如果您的建構會修改這個變數,請務必附加,而不要用指派的方式。

每個依附元件都會向您的建構作業曝露設定檔套件。這些是使用 find_package 指令匯入。此指令會搜尋與指定套件名稱和版本相符的設定檔套件,並曝露要在建構作業中使用的目標。舉例來說,假使您的應用程式定義 libapp.so,且使用 cURL,您的 CMakeLists.txt 應該包含以下內容:

add_library(app SHARED app.cpp)

# Add these two lines.
find_package(curl REQUIRED CONFIG)
target_link_libraries(app curl::curl)

app.cpp 現在可以 #include "curl/curl.h",但 libapp.so 會在建構時自動連結至 libcurl.so,應用程式也會包含 libcurl.so

在 AAR 中發布原生程式庫

AGP 4.1 新增了建立原生 AAR 的功能。

如要匯出原生程式庫,請將以下內容加入程式庫專案的 build.gradle.kts 檔案的 android 區塊中:

Kotlin


buildFeatures {
    prefabPublishing = true
}

prefab {
    create("mylibrary") {
      headers = "src/main/cpp/mylibrary/include"
    }

    create("myotherlibrary") {
        headers = "src/main/cpp/myotherlibrary/include"
    }
}

Groovy


buildFeatures {
    prefabPublishing true
}

prefab {
    mylibrary {
      headers "src/main/cpp/mylibrary/include"
    }

    myotherlibrary {
        headers "src/main/cpp/myotherlibrary/include"
    }
}

在此範例中,從 ndk-build 或 CMake 外部原生建構作業的 mylibrarymyotherlibrary 程式庫會封裝在建構產生的 AAR 中,並且每個都會將標頭從指定目錄匯出到他們的依附元件。

依附元件順序

依附元件的列出順序會指出各存放區的優先順序:第一個程式庫的優先順序高於第二個,第二個程式庫的優先順序高於第三個,依此類推。假使資源合併資訊清單元素合併至應用程式,應用程式順序就相當重要。

舉例來說,假使您的專案宣告了下列項目:

  • LIB_ALIB_B 上的依附元件 (依順序)
  • LIB_A 則取決於 LIB_CLIB_D (依順序)
  • LIB_B 也受到 LIB_C 影響

固定依附元件順序如下:

  1. LIB_A
  2. LIB_D
  3. LIB_B
  4. LIB_C

這可確保 LIB_ALIB_B 能覆寫 LIB_C;並且 LIB_D 的優先順序高於 LIB_B,因為 LIB_A (視實際情況而定) 的優先順序高於 LIB_B

如要進一步瞭解如何合併不同專案來源/依附元件的資訊清單,請參閱「合併多個資訊清單檔案」。

檢視模組依附元件

部分直接依附元件可能有自己的依附元件。這就是所謂的遞移依附元件。Gradle 會自動為您收集並新增這類依附元件,讓您不必手動宣告各項遞移依附元件。Gradle 適用的 Android 外掛程式提供的工作會顯示 Gradle 解析特定模組的依附元件清單。

各個模組也會依據建構變數、測試來源集和類別路徑將依附元件分組。以下是應用程式模組偵錯類別變數的執行階段類別路徑,以及編譯檢測設備測試來源集的類別路徑的範例報表。

debugRuntimeClasspath - Dependencies for runtime/packaging
+--- :mylibrary (variant: debug)
+--- com.google.android.material:material:1.0.0@aar
+--- androidx.appcompat:appcompat:1.0.2@aar
+--- androidx.constraintlayout:constraintlayout:1.1.3@aar
+--- androidx.fragment:fragment:1.0.0@aar
+--- androidx.vectordrawable:vectordrawable-animated:1.0.0@aar
+--- androidx.recyclerview:recyclerview:1.0.0@aar
+--- androidx.legacy:legacy-support-core-ui:1.0.0@aar
...

debugAndroidTest
debugAndroidTestCompileClasspath - Dependencies for compilation
+--- androidx.test.ext:junit:1.1.0@aar
+--- androidx.test.espresso:espresso-core:3.1.1@aar
+--- androidx.test:runner:1.1.1@aar
+--- junit:junit:4.12@jar
...

如要執行工作,請依照下列步驟操作:

  1. 依序選取「View」>「Tool Windows」>「Gradle」,或者點選工具視窗列中的「Gradle」圖示
  2. 展開「AppName」>「Tasks」>「Android」,然後按兩下「androidDependencies」。Gradle 執行工作之後,「Run」視窗應該會開啟以顯示輸出內容。

如要進一步瞭解如何管理 Gradle 中的依附元件,請參閱 Gradle 使用手冊中的「依附元件管理基本資訊」。

修正依附元件解決方案錯誤

在應用程式專案中加入多個依附元件時,這些直接和遞移的依附元件可能會彼此衝突。Android Gradle 外掛程式會試著圓滿地解決這些衝突,但有些衝突可能會導致編譯時間或執行階段錯誤。

為協助您調查哪些依附元件導致錯誤,請查看應用程式的依附元件樹狀結構,找出重複出現或衝突版本的依附元件。

假使您無法辨別重複的依附元件,請嘗試使用 Android Studio 的 UI 搜尋包含重複類別的依附元件,如下所示:

  1. 在選單列中依序選取「Navigate」>「Class」
  2. 在彈出式搜尋對話方塊中,確定已勾選「Include non-project items」旁的方塊。
  3. 輸入建構錯誤中顯示的類別名稱。
  4. 檢查含有類別的依附元件結果。

以下各節說明您可能會遇到的各種依附元件的解決錯誤及修正方式。

修正重複的類別錯誤

假使類別在執行階段類別路徑上多次出現,您會看到如下的錯誤:

Program type already present com.example.MyClass

此錯誤的常見原因如下:

  • 二進位檔依附元件包括一個程式庫,您的應用程式也將其作為直接依附元件包含在內。舉例來說,您的應用程式宣告了程式庫 A 和程式庫 B 的直接依附元件,但程式庫 A 的二進位檔中已包含程式庫 B。
    • 如要解決此問題,請移除程式庫 B 作為直接依附元件。
  • 您的應用程式在同一個程式庫中,儲存本機二進位檔依附元件和遠端二進位檔依附元件。
    • 如要解決此問題,請移除其中一個二進位檔依附元件。

修正類別路徑之間的衝突

Gradle 解析編譯類別路徑時,會先解析執行階段類別路徑,並使用結果來決定要將哪些依附元件版本新增至編譯類別路徑。換句話說,執行階段類別路徑會判斷下游類別路徑中相同依附元件的必要版本號碼。

您應用程式的執行階段類別路徑也會決定 Gradle 需要的應版本號碼,才能比對應用程式的測試 APK 的執行階段類別路徑。圖 1 說明類別路徑的階層結構。

圖 1 出現在多個類別路徑中的依附元件版本編號必須符合此階層。

當相同依附元件的不同版本出現在多個類路徑中,便可能會發生衝突。舉例來說,當您的應用程式包含使用 implementation 依附元件設定的依附元件版本,而程式庫模組包含使用 runtimeOnly 設定的另一個依附元件版本時,便可能會發生衝突。

解決執行階段中編譯依附元件和編譯時間類別路徑時,Android Gradle 外掛程式 3.3.0 以上版本會嘗試自動修正特定的下游版本衝突。舉例來說,當執行階段類別路徑內含程式庫 A 版本 2.0,而編譯類別路徑內含程式庫 A 版本 1.0,此時外掛程式會自動將編譯類別路徑內的依附元件更新為程式庫 A 版本 2.0,以便防止發生錯誤。

然而,假使執行階段類別路徑包含程式庫 A 版本 1.0,且編譯類別路徑包含程式庫 A 版本 2.0,則外掛程式不會將編譯類別路徑的依附元件降級至程式庫 A 版本 1.0,但您仍然會取得錯誤,如下所示:

Conflict with dependency 'com.example.library:some-lib:2.0' in project 'my-library'.
Resolved versions for runtime classpath (1.0) and compile classpath (2.0) differ.

如要解決這個問題,請按照下列其中一種做法進行:

  • 將所需依附元件版本新增為程式庫模組的 api 依附元件。也就是說,只有您的程式庫模組會宣告依附元件,但應用程式模組也可以遞移地存取其 API。
  • 或者,您可以在這兩種模組中宣告依附元件,但請務必確保每個模組都使用相同版本的依附元件。建議設定全專案的屬性,確保整個專案中各項依附元件的版本保持一致。

套用自訂建構邏輯

本節說明當您想要擴充 Android Gradle 外掛程式或自行編寫外掛程式時實用的進階主題。

將變化版本依附元件發布至自訂邏輯

程式庫具有可供其他專案或子專案使用的功能。發布程式庫是提供程式庫給消費者的過程。程式庫可控管消費者在編譯時間和執行階段期間可存取哪些依附元件。

有兩種不同的設定會沿用每個類別路徑的遞移依附元件,讓消費者必須依下列說明使用程式庫:

  • variant_nameApiElements:這項設定會沿用消費者在編譯期間可用的遞移依附元件。
  • variant_nameRuntimeElements:這項設定會沿用執行階段提供給消費者的遞移依附元件。

如要進一步瞭解不同設定之間的關係,請參閱「Java 程式庫外掛程式設定」。

自訂依附元件解決策略

專案可能包含相同程式庫中兩個不同版本的依附元件,進而產生依附元件衝突。舉例來說,假使專案依附了模組 A 的第 1 版和模組 B 的第 2 版,而 A 模組間接仰賴模組 B 的第 3 版,則會產生依附元件版本衝突。

為解決這項衝突,Android Gradle 外掛程式採用下列依附元件解決方案:當外掛程式檢測到同一個模組的不同版本在依附元件圖形中時,根據預設,會選擇版本編號最高的那個。

然而,這項策略不一定每次都能如預期運作。如要自訂依附元件解決策略,請使用下列設定來解決工作需要的某個變數的特定依附元件:

  • variant_nameCompileClasspath:此設定包含特定變數的編譯類別路徑的解析度策略。
  • variant_nameRuntimeClasspath:此設定包含特定變數執行階段類別路徑的解析度策略。

您可透過 Android Gradle 外掛程式取得 getter,以便存取每個變數的設定物件。因此,您可以使用變數 API 查詢依附元件解析度,如下方範例所示:

Kotlin

android {
    applicationVariants.all {
        // Return compile configuration objects of a variant.
        compileConfiguration.resolutionStrategy {
        // Use Gradle's ResolutionStrategy API
        // to customize how this variant resolves dependencies.
            ...
        }
        // Return runtime configuration objects of a variant.
        runtimeConfiguration.resolutionStrategy {
            ...
        }
        // Return annotation processor configuration of a variant.
        annotationProcessorConfiguration.resolutionStrategy {
            ...
        }
    }
}

Groovy

android {
    applicationVariants.all { variant ->
        // Return compile configuration objects of a variant.
        variant.getCompileConfiguration().resolutionStrategy {
        // Use Gradle's ResolutionStrategy API
        // to customize how this variant resolves dependencies.
            ...
        }
        // Return runtime configuration objects of a variant.
        variant.getRuntimeConfiguration().resolutionStrategy {
            ...
        }
        // Return annotation processor configuration of a variant.
        variant.getAnnotationProcessorConfiguration().resolutionStrategy {
            ...
        }
    }
}

Play 管理中心的依附元件資訊

建構應用程式時,AGP 會加入中繼資料,用於描述編譯至應用程式中的程式庫依附元件。在應用程式上傳期間,Play 管理中心會檢查這些中繼資料,針對應用程式使用的 SDK 和依附元件提供快訊,並在部分情況下提供可行的意見回饋,以解決這些問題。

資料會經過壓縮、由 Google Play 簽署金鑰加密,並儲存在所發布應用程式的簽署區塊。建議您保留這個依附元件檔案,以提供安全良好的使用者體驗。您可以在模組的 build.gradle.kts 檔案中加入下列 dependenciesInfo 區塊,即可選擇不採用。

android {
    dependenciesInfo {
        // Disables dependency metadata when building APKs.
        includeInApk = false
        // Disables dependency metadata when building Android App Bundles.
        includeInBundle = false
    }
}

如要進一步瞭解我們的政策,以及依附元件的潛在問題,請參閱「在應用程式中使用第三方 SDK」的支援頁面。

SDK 深入分析

Android Studio 會在 build.gradle 檔案和「Project Structure」對話方塊中顯示 Lint 警告,表示已標記為過時的公開 SDK 由其作者在「Google Play SDK Index」索引中列出。這是更新這些依附元件的訊號,因為使用過時版本可能會導致日後無法發布至 Google Play 管理中心。