添加 build 依赖项

利用 Android Studio 中的 Gradle 构建系统,您可以轻松地将外部二进制文件或其他库模块作为依赖项添加到您的 build 中。这些依赖项可位于您的计算机上或远程仓库中,并且它们声明的所有传递依赖项也会自动包含在内。 本页介绍了如何在您的 Android 项目中使用依赖项,包括有关 Android Plugin for Gradle 特有的行为和配置的详细信息。如需更深入地了解 Gradle 依赖项的概念,您还应该参阅 Gradle 依赖项管理指南。但请注意,您的 Android 项目只能使用本页上定义的依赖项配置

依赖项类型

如需向您的项目添加依赖项,请在模块的 build.gradle 文件的 dependencies 代码块中指定依赖项配置,如 implementation

例如,应用模块的以下 build.gradle 文件包含三种不同类型的依赖项:

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

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

implementation project(':mylibrary')

Kotlin

implementation(project(":mylibrary"))

这声明了对一个名为“mylibrary”(此名称必须与您的 settings.gradle 文件中使用 include: 定义的库名称相符)的 Android 库模块的依赖关系。 在构建您的应用时,构建系统会编译该库模块,并将生成的编译内容打包到应用中。

本地二进制文件依赖项

Groovy

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

Kotlin

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

Gradle 声明了对项目的 module_name/libs/ 目录中 JAR 文件的依赖关系(因为 Gradle 会读取 build.gradle 文件的相对路径)。

或者,您也可以按如下方式指定各个文件:

Groovy

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

Kotlin

  implementation(files("libs/foo.jar", "libs/bar.jar"))
  
远程二进制文件依赖项

Groovy

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

Kotlin

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

这实际上是以下代码的简写形式:

Groovy

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

Kotlin

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

这声明了对“com.example.android”命名空间组内的 12.3 版“app-magic”库的依赖关系。

注意:此类远程依赖项要求您声明 Gradle 应在其中查找库的相应远程仓库。 如果本地不存在相应的库,那么当 build 需要它时(例如,当您点击 Sync Project with Gradle Files 图标 或运行 build 时),Gradle 会从远程站点提取它。

如果您在编译时依赖 AGP 依赖项,请务必将其添加为显式依赖项。由于 AGP 在内部使用 api/implementation 配置,因此某些工件可能会从您的编译类路径中移除,而编译类路径可能会更改。

原生依赖项

从 Android Gradle 插件 4.0 开始,也可以按照本页所述的方式导入原生依赖项。

对提供原生库的 AAR 的依赖会自动使这些库可供 externalNativeBuild 所使用的构建系统使用。如需从代码访问这些库,您必须在原生构建脚本中链接到这些库。请参阅本页中的使用原生依赖项

依赖项配置

dependencies 代码块内,您可以从多种不同的依赖项配置中选择其一(如上面所示的 implementation)来声明库依赖项。每种依赖项配置都向 Gradle 提供了有关如何使用该依赖项的不同说明。下表介绍了您可以对 Android 项目中的依赖项使用的各种配置。此表还将这些配置与自 Android Gradle 插件 3.0.0 起废弃的配置进行了比较。

配置 行为
implementation Gradle 会将依赖项添加到编译类路径,并将依赖项打包到 build 输出。不过,当您的模块配置 implementation 依赖项时,会让 Gradle 了解您不希望该模块在编译时将该依赖项泄露给其他模块。也就是说,其他模块只有在运行时才能使用该依赖项。

使用此依赖项配置代替 apicompile(已废弃)可以显著缩短构建时间,因为这样可以减少构建系统需要重新编译的模块数。例如,如果 implementation 依赖项更改了其 API,Gradle 只会重新编译该依赖项以及直接依赖于它的模块。大多数应用和测试模块都应使用此配置。

api Gradle 会将依赖项添加到编译类路径和 build 输出。当一个模块包含 api 依赖项时,会让 Gradle 了解该模块要以传递方式将该依赖项导出到其他模块,以便这些模块在运行时和编译时都可以使用该依赖项。

此配置的行为类似于 compile(现已废弃),但使用它时应格外小心,只能对您需要以传递方式导出到其他上游消费者的依赖项使用它。 这是因为,如果 api 依赖项更改了其外部 API,Gradle 会在编译时重新编译所有有权访问该依赖项的模块。 因此,拥有大量的 api 依赖项会显著增加构建时间。 除非要将依赖项的 API 公开给单独的模块,否则库模块应改用 implementation 依赖项。

compileOnly Gradle 只会将依赖项添加到编译类路径(也就是说,不会将其添加到 build 输出)。如果您创建 Android 模块时在编译期间需要相应依赖项,但它在运行时可有可无,此配置会很有用。

如果您使用此配置,那么您的库模块必须包含一个运行时条件,用于检查是否提供了相应依赖项,然后适当地改变该模块的行为,以使该模块在未提供相应依赖项的情况下仍可正常运行。这样做不会添加不重要的瞬时依赖项,因而有助于减小最终应用的大小。 此配置的行为类似于 provided(现已废弃)。

注意:您不能将 compileOnly 配置与 AAR 依赖项配合使用。

runtimeOnly Gradle 只会将依赖项添加到 build 输出,以便在运行时使用。也就是说,不会将其添加到编译类路径。 此配置的行为类似于 apk(现已废弃)。
annotationProcessor

如需添加对作为注解处理器的库的依赖,您必须使用 annotationProcessor 配置将其添加到注解处理器的类路径。这是因为,使用此配置可以将编译类路径与注解处理器类路径分开,从而提高 build 性能。如果 Gradle 在编译类路径上找到注解处理器,则会禁用避免编译功能,这样会对构建时间产生负面影响(Gradle 5.0 及更高版本会忽略在编译类路径上找到的注解处理器)。

如果 JAR 文件包含以下文件,则 Android Gradle 插件会假定依赖项是注解处理器:

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

如果插件检测到编译类路径上包含注解处理器,则会产生 build 错误。

注意:Kotlin 项目应使用 kapt 声明注解处理器依赖项。

lintChecks

使用此配置可以添加您希望 Gradle 在构建项目时执行的 lint 检查。

注意:使用 Android Gradle 插件 3.4.0 及更高版本时,此依赖项配置不再将 lint 检查打包在 Android 库项目中。如需将 lint 检查依赖项包含在 AAR 库中,请使用下面介绍的 lintPublish 配置。

lintPublish 在 Android 库项目中使用此配置可以添加您希望 Gradle 编译成 lint.jar 文件并打包在 AAR 中的 lint 检查。这会使得使用 AAR 的项目也应用这些 lint 检查。如果您之前使用 lintChecks 依赖项配置将 lint 检查添加到已发布的 AAR 中,则需要迁移这些依赖项以改用 lintPublish 配置。

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')
}

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"))
}
apk Gradle 只会将依赖项添加到 build 输出,以便在运行时使用。也就是说,不会将其添加到编译类路径。 此配置已废弃(在 AGP 1.0-4.2 中可用)。
compile Gradle 会将依赖项添加到编译类路径和 build 输出,并将依赖项导出到其他模块。此配置已废弃(在 AGP 1.0-4.2 中可用)。
provided Gradle 只会将依赖项添加到编译类路径(也就是说,不会将其添加到 build 输出)。此配置已废弃(在 AGP 1.0-4.2 中可用)。

以上所有配置会将依赖项应用于所有 build 变体。如果您只想为特定的 build 变体源代码集或测试源代码集声明依赖项,则必须将配置名称的首字母大写,并在其前面加上 build 变体或测试源代码集的名称作为前缀。

例如,如需只向“free”产品变种添加 implementation 依赖项(使用远程二进制文件依赖项),请使用如下所示的代码:

Groovy

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

Kotlin

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

不过,如果您想为将产品变种和 build 类型组合在一起的变体添加依赖项,就必须在 configurations 代码块中初始化配置名称。以下示例向“freeDebug”build 变体添加了 runtimeOnly 依赖项(使用本地二进制文件依赖项)。

Groovy

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

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

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"))))
}

如需为本地测试和插桩测试添加 implementation 依赖项,请使用如下所示的代码:

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'
}

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")
}

不过,某些配置在这种情况下没有意义。例如,因为其他模块不能依赖于 androidTest,所以如果您使用 androidTestApi 配置,会收到以下警告:

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

添加注释处理器

如果将注释处理器添加到编译类路径,您将看到一条与以下内容类似的错误消息:

Error: Annotation processors must be explicitly declared now.

如需解决此错误,请使用 annotationProcessor 配置依赖项,将注解处理器添加到您的项目,如下所示:

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'
}

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")
}

注意:Android Plugin for Gradle 3.0.0 及更高版本不再支持 android-apt 插件

向注解处理器传递参数

如果需要向注解处理器传递参数,您可以使用模块 build 配置中的 AnnotationProcessorOptions 代码块执行此操作。例如,如果要以键值对形式传递基元数据类型,您可以使用 argument 属性,如下所示:

Groovy

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

Kotlin

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

不过,在使用 Android Gradle 插件 3.2.0 及更高版本时,您需要使用 Gradle 的 CommandLineArgumentProvider 接口传递表示文件或目录的处理器参数。

借助 CommandLineArgumentProvider,您或注解处理器创建者可将增量 build 属性类型注解应用于每个参数,从而提高增量 build 和缓存整洁 build 的正确性和性能。

例如,下面的类实现了 CommandLineArgumentProvider 并注释了处理器的每个参数。此外,此示例还使用了 Groovy 语言语法,并且直接包含在模块的 build.gradle 文件中。

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 {...}

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 {...}

定义一个实现 CommandLineArgumentProvider 的类后,您需要创建一个实例,并使用 annotationProcessorOptions.compilerArgumentProvider 方法将该实例传递给 Android 插件,如下所示:

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"))
            }
        }
    }
}

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")))
            }
        }
    }
}

如需详细了解实现 CommandLineArgumentProvider 如何帮助提高 build 性能,请阅读缓存 Java 项目

停用注解处理器错误检查

如果编译类路径中的依赖项包含您不需要的注解处理器,您可以通过将以下代码添加到 build.gradle 文件来停用错误检查。请注意,您添加到编译类路径中的注解处理器仍不会被添加到处理器类路径中。

Groovy

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

Kotlin

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

如果您使用 Kotlin 和 kapt

Groovy

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

Kotlin

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

如果在将项目的注解处理器迁移到处理器类路径后遇到问题,您可以通过将 includeCompileClasspath 设为 true,允许编译类路径中包含注解处理器。不过,不建议将此属性设为 true,在 Android 插件的未来更新中将会移除用来执行此操作的选项。

排除传递依赖项

随着应用的范围不断扩大,它可能会包含许多依赖项,包括直接依赖项和传递依赖项(应用中导入的库所依赖的库)。 如需排除不再需要的传递依赖项,您可以使用 exclude 关键字,如下所示:

Groovy

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

Kotlin

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

从测试配置中排除传递依赖项

如果您需要从测试中排除某些传递依赖项,上面所示的代码示例可能无法按预期发挥作用。这是因为,测试配置(例如 androidTestImplementation)扩展了模块的 implementation 配置。也就是说,当 Gradle 解析配置时,测试配置始终包含 implementation 依赖项。

因此,如需从测试中排除传递依赖项,则必须在执行代码时执行此操作,如下所示:

Groovy

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

Kotlin

android.testVariants.all {
    compileConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
    runtimeConfiguration.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 项目会在项目的 settings.gradle 文件中将 Google 的 Maven 制品库Maven 中央制品库指定为仓库位置,如下所示:

Groovy


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

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()
    }
}

Kotlin


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

或者,您也可以按如下方式声明特定的 Maven 或 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'
        }
    }
}

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")
    }
}

如需了解详情,请参阅 Gradle 仓库指南

Google 的 Maven 制品库

Google 的 Maven 制品库中提供了以下 Android 库的最新版本:

您可以在 Google 的 Maven 制品库索引中查看所有可用的工件(如需了解以编程方式访问,请参阅下文)。

如需将其中某个库添加到您的 build 中,请在顶级 build.gradle 文件中包含 Google 的 Maven 制品库:

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/'.
    }
}

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/".
    }
}

然后,将所需的库添加到模块的 dependencies 代码块中。例如,appcompat 库如下所示:

Groovy


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

Kotlin


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

不过,如果您在尝试使用旧版上述库时依赖项失败,则表明 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-version.ext

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

SDK 管理器中的离线仓库

对于无法从 Google Maven 制品库中获得的库(通常是旧版库),您必须从 SDK 管理器下载离线 Google 仓库软件包。

然后,您可以照常将这些库添加到 dependencies 代码块中。

离线库保存在 android_sdk/extras/ 中。

Android Gradle 插件可以使用的原生依赖项

AAR 库可以包含 Android Gradle 插件可以使用的原生依赖项。AGP 还能生成用于向使用者公开原生库的 AAR。

使用原生依赖项

从 Android Gradle 插件 4.0 开始,我们已支持从您的 build.gradle 文件所关联的 AAR 中导入 C/C++ 依赖项。Gradle 会自动将这些依赖项提供给原生构建系统,但构建系统必须经过配置才能使用导入的库和头文件。由于 C/C++ 依赖项会以 AAR 的形式分发,因此以下关于通用 AAR 的链接可能很有用:

  • 创建 Android 库,可获取通用 AAR 文档,并了解如何将其集成到您的项目中,尤其是当您想要使用 AAR 作为本地 C/C++ 依赖项时。
  • 添加 build 依赖项,了解有关如何将依赖项(尤其是远程依赖项)添加到您的 build.gradle 文件。

本文档重点介绍了如何配置原生构建系统,并假定您已将 C/C++ 依赖项 AAR 添加到您项目的 Gradle 构建环境中。

AAR 中的原生依赖项

Gradle 模块中的 AAR 依赖项可公开原生库供您的应用使用。在 AAR 中,prefab 目录包含 Prefab 软件包,后者包含原生依赖项的头文件和库。

每个依赖项最多可公开一个包含一个或多个模块的 Prefab 软件包。Prefab 模块是一个单独的库,它可以是共享库或静态库,也可以是仅针对头文件的库。

软件包和模块的名称均已知时,才能使用相应库。按照惯例,软件包名称应与 Maven 工件名称相匹配,模块名称应与 C/C++ 库名称相匹配,但并非必须如此。请参考相应依赖项的文档来确定依赖项所用的名称。

构建系统配置

必须为您的 Android Gradle 模块启用 prefab 功能。

为此,请将以下内容添加到您模块的 build.gradle 文件的 android 代码块中:

Groovy

buildFeatures {
  prefab true
}

Kotlin

buildFeatures {
  prefab = true
}

(可选)在项目的 gradle.properties 文件中配置一个版本

android.prefabVersion=2.0.0

通常,所选的默认 AGP 版本可满足您的需求。仅当在需要解决某个 bug 或想获取某个新功能时,才需要选择其他版本。

从 AAR 导入的依赖项将通过 CMAKE_FIND_ROOT_PATH 向 CMake 公开。当系统调用 CMake 时,Gradle 会自动设置此值,因此如果您的 build 修改了此变量,请务必确保对其附加相应值而不是直接赋值。

每个依赖项都会向您的 build 公开 config-file 软件包。这些软件包是通过 find_package 命令导入的。此命令会搜索与给定软件包名称和版本匹配的 config-file 软件包,并公开为您的 build 指定的目标。例如,如果您的应用定义了 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.solibcurl.so 相关联,并将 libcurl.so 包含在应用中。

在 AAR 中发布原生库

在 AGP 4.1 中首次添加了创建原生 AAR 的功能。

如需导出原生库,请将以下代码添加到库项目的 build.gradle 文件的 android 代码块中:

Groovy


buildFeatures {
    prefabPublishing true
}

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

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

Kotlin


buildFeatures {
    prefabPublishing = true
}

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

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

在本例中,您的 ndk-build 或 CMake 外部原生 build 中的 mylibrarymyotherlibrary 库会打包到您的 build 生成的 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 将会自动为您收集并添加这些传递依赖项,无需您手动逐一加以声明。 Android Plugin for Gradle 提供了一项任务,用来列出 Gradle 为给定模块解析的依赖项。

对于每个模块,报告还会根据 build 变体、测试源代码集和类路径对依赖项进行分组。下面是一个应用模块的依赖项示例报告,其中按该模块的调试 build 变体的运行时类路径和该模块的插桩测试源代码集的编译类路径对依赖项进行了分组。

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 的界面搜索包含重复类的依赖项,具体操作步骤如下:

  1. 从菜单栏中依次选择 Navigate > Class
  2. 在弹出式搜索对话框中,确保已勾选 Include non-project items 旁边的框。
  3. 输入 build 错误中出现的类的名称。
  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 查询依赖项解析,如以下示例所示:

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 {
            ...
        }
    }
}

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 {
            ...
        }
    }
}

Play 管理中心的依赖项信息

使用 AGP 4.0.0 及更高版本构建应用时,该插件包含描述已编译到应用中的库依赖项的元数据。上传应用时,Play 管理中心会检查此元数据,以便为您提供有关应用使用的 SDK 和依赖项的已知问题提醒,在某些情况下还会提供解决这些问题的切实可行的反馈。

数据经过压缩,并由 Google Play 签名密钥加密,然后存储在您的发布应用的签名分块中。我们建议您保留此依赖项文件,以提供安全的良好用户体验。不过,如果您不希望分享这些信息,可以通过在模块的 build.gradle 文件中添加以下 dependenciesInfo 代码块来选择取消分享:

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

如需详细了解我们的政策以及依赖项可能存在的问题,请参阅有关在应用中使用第三方 SDK 的支持页面。

SDK 数据分析

对于已被作者在 Google Play SDK 索引中标记为过时的公共 SDK,Android Studio 会在 build.gradle 文件和“Project Structure”对话框中显示 lint 警告。您可据此更新这些依赖项,因为如果继续使用过时的版本,您日后可能会无法将内容发布到 Google Play 管理中心。