Android Gradle Plugin 4.0.0(2020 年 4 月)

此版本的 Android 插件需要满足以下要求

4.0.1(2020 年 7 月)

此次小版本更新支持与 Android 11 中软件包可见性的新默认设置和功能兼容。

在之前的 Android 版本中,可以查看设备上安装的所有应用的列表。从 Android 11(API 级别 30)开始,应用默认只能访问已安装软件包的经过滤的列表。如需查看系统上更广泛的应用列表,您现在需要在应用或库的 Android 清单中添加一个 <queries> 元素

Android Gradle plugin 4.1 及更高版本已经与新的 <queries> 声明兼容;但是,旧版本不兼容。如果您添加 <queries> 元素,或者开始依赖支持以 Android 11 为目标的库或 SDK,在构建应用时可能会遇到清单合并错误。

为了解决此问题,我们发布了一组适用于 AGP 3.3 及更高版本的补丁。如果您使用的是旧版 AGP,请升级到以下版本之一

最低版本 默认版本 备注
Gradle 6.1.1 6.1.1 如需了解详情,请参阅更新 Gradle
SDK Build Tools 29.0.2 29.0.2 安装配置 SDK Build Tools。

如需了解关于此新功能的更多信息,请参阅Android 11 中的软件包可见性

新功能

此版本的 Android Gradle 插件包含以下新功能。

支持 Android Studio Build Analyzer

Build Analyzer 窗口可帮助您了解并诊断构建过程中的问题,例如禁用的优化和配置不当的任务。当您将 Android Studio 4.0 及更高版本与 Android Gradle plugin 4.0.0 及更高版本配合使用时,即可使用此功能。您可以通过以下方式从 Android Studio 打开 Build Analyzer 窗口

  1. 如果您尚未构建应用,请通过菜单栏选择 Build > Make Project 来构建您的应用。
  2. 通过菜单栏选择 View > Tool Windows > Build
  3. Build 窗口中,通过以下任一方式打开 Build Analyzer 窗口
    • Android Studio 完成项目构建后,点击 Build Analyzer 标签页。
    • Android Studio 完成项目构建后,点击 Build Output 窗口右侧的链接。

Build Analyzer 窗口将可能的构建问题组织在左侧的树形结构中。您可以检查并点击每个问题,以在右侧面板中调查其详细信息。当 Android Studio 分析您的构建时,它会计算决定构建时长的任务集,并提供可视化信息以帮助您了解每个任务的影响。您还可以通过展开 Warnings 节点获取警告的详细信息。

如需了解详情,请阅读识别构建速度退化问题

D8 和 R8 中的 Java 8 库脱糖

Android Gradle 插件现在支持使用多种 Java 8 语言 API,而无需为您的应用设置最低 API 级别。

通过一个名为 脱糖 的过程,Android Studio 3.0 及更高版本中的 DEX 编译器 D8 已提供了对 Java 8 语言功能(例如 lambda 表达式、默认接口方法、try-with-resources 等)的大力支持。在 Android Studio 4.0 中,脱糖引擎已得到扩展,能够对 Java 语言 API 进行脱糖。这意味着您现在可以将仅在最新 Android 版本中提供的标准语言 API(例如 java.util.streams)包含在支持旧版 Android 的应用中。

此版本支持以下 API 集

  • 顺序流 (java.util.stream)
  • java.time 的一个子集
  • java.util.function
  • java.util.{Map,Collection,Comparator} 的近期新增功能
  • Optional(java.util.Optionaljava.util.OptionalIntjava.util.OptionalDouble)以及其他一些对上述 API 有用的新类
  • java.util.concurrent.atomic 的一些新增功能(AtomicIntegerAtomicLongAtomicReference 中的新方法)
  • ConcurrentHashMap(包含 Android 5.0 的错误修复)

为了支持这些语言 API,D8 会编译一个单独的库 DEX 文件,其中包含缺失 API 的实现,并将其包含在您的应用中。脱糖过程会重写您的应用代码,以便在运行时改用此库。

为了启用对这些语言 API 的支持,请在您的应用模块build.gradle 文件中添加以下内容

android {
  defaultConfig {
    // Required when setting minSdkVersion to 20 or lower
    multiDexEnabled true
  }

compileOptions { // Flag to enable support for the new language APIs coreLibraryDesugaringEnabled true // Sets Java compatibility to Java 8 sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }

dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.4' }

android {
  defaultConfig {
    // Required when setting minSdkVersion to 20 or lower
    multiDexEnabled = true
  }

compileOptions { // Flag to enable support for the new language APIs isCoreLibraryDesugaringEnabled = true // Sets Java compatibility to Java 8 sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } }

dependencies { coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.0.4") }

请注意,在以下情况下,您可能还需要在库模块build.gradle 文件中包含上述代码片段

  • 库模块的插桩测试使用这些语言 API(直接使用,或通过库模块或其依赖项使用)。这是为了确保为您的插桩测试 APK 提供缺失的 API。

  • 您希望单独对库模块运行 lint。这是为了帮助 lint 识别语言 API 的有效用法,并避免报告误报警告。

启用或禁用构建功能的新选项

Android Gradle plugin 4.0.0 引入了一种新的方法来控制您希望启用和禁用哪些构建功能,例如 View Binding 和 Data Binding。添加新功能时,它们默认处于禁用状态。然后,您可以使用 buildFeatures 块仅启用您想要的功能,这有助于优化项目的构建性能。您可以在模块级 build.gradle 文件中为每个模块设置选项,如下所示

android {
  // The default value for each feature is shown below. You can change the value to
  // override the default behavior.
  buildFeatures {
    // Determines whether to generate a BuildConfig class.
    buildConfig = true
    // Determines whether to support View Binding.
    // Note that the viewBinding.enabled property is now deprecated.
    viewBinding = false
    // Determines whether to support Data Binding.
    // Note that the dataBinding.enabled property is now deprecated.
    dataBinding = false
    // Determines whether to generate binder classes for your AIDL files.
    aidl = true
    // Determines whether to support RenderScript.
    renderScript = true
    // Determines whether to support injecting custom variables into the module’s R class.
    resValues = true
    // Determines whether to support shader AOT compilation.
    shaders = true
  }
}
android {
  // The default value for each feature is shown below. You can change the value to
  // override the default behavior.
  buildFeatures {
    // Determines whether to generate a BuildConfig class.
    buildConfig = true
    // Determines whether to support View Binding.
    // Note that the viewBinding.enabled property is now deprecated.
    viewBinding = false
    // Determines whether to support Data Binding.
    // Note that the dataBinding.enabled property is now deprecated.
    dataBinding = false
    // Determines whether to generate binder classes for your AIDL files.
    aidl = true
    // Determines whether to support RenderScript.
    renderScript = true
    // Determines whether to support injecting custom variables into the module’s R class.
    resValues = true
    // Determines whether to support shader AOT compilation.
    shaders = true
  }
}

您还可以通过在项目的 gradle.properties 文件中包含以下一个或多个选项来指定项目中所有模块的这些功能的默认设置,如下所示。请注意,您仍然可以在模块级 build.gradle 文件中使用 buildFeatures 块来覆盖这些项目范围的默认设置。

android.defaults.buildfeatures.buildconfig=true
android.defaults.buildfeatures.aidl=true
android.defaults.buildfeatures.renderscript=true
android.defaults.buildfeatures.resvalues=true
android.defaults.buildfeatures.shaders=true

Feature-on-feature 依赖项

在之前的 Android Gradle 插件版本中,所有 feature 模块只能依赖应用的 base 模块。使用 Android Gradle plugin 4.0.0 时,您现在可以包含一个依赖于另一个 feature 模块的 feature 模块。也就是说,一个 :video feature 可以依赖于 :camera feature,而 :camera feature 依赖于 base 模块,如下图所示。

Feature on feature dependencies

Feature 模块 :video 依赖于 feature :camera,而后者依赖于 base :app 模块。

这意味着当您的应用请求下载一个 feature 模块时,应用也会下载它所依赖的其他 feature 模块。为应用创建 feature 模块后,您可以在模块的 build.gradle 文件中声明 feature-on-feature 依赖项。例如,:video 模块声明对 :camera 的依赖项,如下所示

// In the build.gradle file of the ':video' module.
dependencies {
  // All feature modules must declare a dependency
  // on the base module.
  implementation project(':app')
  // Declares that this module also depends on the 'camera'
  // feature module.
  implementation project(':camera')
  ...
}
// In the build.gradle file of the ':video' module.
dependencies {
    // All feature modules must declare a dependency
    // on the base module.
    implementation(project(":app"))
    // Declares that this module also depends on the 'camera'
    // feature module.
    implementation(project(":camera"))
    ...
}

此外,您应该在 Android Studio 中启用 feature-on-feature 依赖项功能(例如,在编辑运行配置时支持该功能),方法是从菜单栏点击 Help > Edit Custom VM Options 并包含以下内容

-Drundebug.feature.on.feature=true

依赖项元数据

使用 Android Gradle plugin 4.0.0 及更高版本构建应用时,该插件会包含描述编译到应用中的依赖项的元数据。上传应用时,Play 管理中心会检查此元数据,为您提供以下好处

  • 获取关于您的应用使用的 SDK 和依赖项已知问题的提醒
  • 接收可操作的反馈以解决这些问题

数据经过压缩,由 Google Play 签名密钥加密,并存储在您发布应用的签名块中。但是,您可以在以下目录的本地中间构建文件中自行检查元数据:<project>/<module>/build/outputs/sdk-dependencies/release/sdkDependency.txt

如果您不希望共享此信息,可以通过在模块的 build.gradle 文件中包含以下内容来选择停用

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

从 AAR 依赖项导入原生库

您现在可以从应用的 AAR 依赖项导入 C/C++ 库。按照下面描述的配置步骤操作后,Gradle 会自动使这些原生库可用于您的外部原生构建系统,例如 CMake。请注意,Gradle 只会使这些库可用于您的构建;您仍必须配置构建脚本才能使用它们。

库使用 Prefab 软件包格式导出。

每个依赖项最多可以公开一个 Prefab 软件包,其中包含一个或多个模块。Prefab 模块是单个库,可以是共享库、静态库或仅头文件库。

通常,软件包名称与 Maven Artifact 名称匹配,模块名称与库名称匹配,但这并非总是如此。由于您需要知道库的软件包和模块名称,因此您可能需要查阅依赖项的文档来确定这些名称。

配置您的外部原生构建系统

要查看需要遵循的步骤,请按照您计划使用的外部原生构建系统的以下步骤操作。

应用的每个包含原生代码的 AAR 依赖项都会公开一个 Android.mk 文件,您需要将其导入到 ndk-build 项目中。您可以使用 import&endash;module 命令导入此文件,该命令会在您的 ndk-build 项目中使用 import&endash;add&endash;path 属性指定的路径中进行搜索。例如,如果您的应用定义了 libapp.so 并使用了 curl,则应在 Android.mk 文件中包含以下内容

  1. 对于 CMake

    add_library(app SHARED app.cpp)

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

  2. 对于 ndk-build

    include $(CLEAR_VARS)
    LOCAL_MODULE := libapp
    LOCAL_SRC_FILES := app.cpp
    # Link libcurl from the curl AAR.
    LOCAL_SHARED_LIBRARIES := curl
    include $(BUILD_SHARED_LIBRARY)

    # If you don't expect that your project will be built using versions of the NDK # older than r21, you can omit this block. ifneq ($(call ndk-major-at-least,21),true) $(call import-add-path,$(NDK_GRADLE_INJECTED_IMPORT_PATH)) endif

    # Import all modules that are included in the curl AAR. $(call import-module,prefab/curl)

包含在 AAR 中的原生依赖项会通过 CMAKE_FIND_ROOT_PATH{: .external} 变量公开给您的 CMake 项目。当调用 CMake 时,此值将由 Gradle 自动设置,因此如果您的构建系统修改此变量,请务必附加而不是赋值。

每个依赖项都会向您的 CMake 构建公開一个 配置文件包{: .external},您可以使用 find_package{: .external} 命令导入它。此命令会搜索与给定软件包名称和版本匹配的配置文件包,并公开它定义的要在构建中使用的目标。例如,如果您的应用定义了 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 打包到 APK 或 app bundle 中。如需更多信息,请参阅 curl prefab 示例{:.external}。

行为变更

使用此版本的插件时,您可能会遇到以下行为变更。

v1/v2 签名配置更新

signingConfig 块中应用签名配置的行为已更改为以下内容

v1 签名

  • 如果显式启用了 v1SigningEnabled,AGP 会执行 v1 应用签名。
  • 如果用户显式禁用了 v1SigningEnabled,则不会执行 v1 应用签名。
  • 如果用户没有显式启用 v1 签名,它会根据 minSdktargetSdk 自动禁用。

v2 签名

  • 如果显式启用了 v2SigningEnabled,AGP 会执行 v2 应用签名。
  • 如果用户显式禁用了 v2SigningEnabled,则不会执行 v2 应用签名。
  • 如果用户没有显式启用 v2 签名,它会根据 targetSdk 自动禁用。

这些更改允许 AGP 根据用户是否显式启用这些标志来禁用签名机制,从而优化构建。在此版本之前,即使显式启用了 v1Signing,也可能会被禁用,这可能会令人困惑。

已移除 featureinstantapp Android Gradle 插件

Android Gradle plugin 3.6.0 已弃用 Feature 插件 (com.android.feature) 和 Instant App 插件 (com.android.instantapp),取而代之的是使用 Dynamic Feature 插件 (com.android.dynamic-feature) 通过 Android App Bundle 构建和打包您的即时应用。

在 Android Gradle plugin 4.0.0 及更高版本中,这些已弃用的插件已完全移除。因此,要使用最新的 Android Gradle 插件,您需要迁移您的即时应用以支持 Android App Bundle。通过迁移即时应用,您可以利用 app bundle 的优势并简化您的应用模块化设计

注意:要在 Android Studio 4.0 及更高版本中打开使用已移除插件的项目,该项目必须使用 Android Gradle plugin 3.6.0 或更低版本。

已移除独立注解处理功能

已移除将注解处理分离到专门任务的能力。此选项用于在纯 Java 项目中使用非增量注解处理器时保持增量 Java 编译;它是通过在 gradle.properties 文件中将 android.enableSeparateAnnotationProcessing 设置为 true 来启用的,但此设置已不再有效。

相反,您应该迁移到使用增量注解处理器以提高构建性能。

includeCompileClasspath 已弃用

Android Gradle 插件不再检查或包含您在编译类路径上声明的注解处理器,并且 annotationProcessorOptions.includeCompileClasspath DSL 属性不再有任何效果。如果您在编译类路径上包含注解处理器,可能会收到以下错误

Error: Annotation processors must be explicitly declared now.

要解决此问题,您必须使用 annotationProcessor 依赖项配置将注解处理器包含在 build.gradle 文件中。如需了解详情,请阅读添加注解处理器

自动打包 CMake 使用的预构建依赖项

之前版本的 Android Gradle 插件要求您使用 jniLibs 显式打包 CMake 外部原生构建使用的所有预构建库。您的模块的 src/main/jniLibs 目录中可能有库,或者可能位于 build.gradle 文件中配置的其他目录中

sourceSets {
  main {
    // The libs directory contains prebuilt libraries that are used by the
    // app's library defined in CMakeLists.txt via an IMPORTED target.
    jniLibs.srcDirs = ['libs']
  }
}
sourceSets {
  main {
    // The libs directory contains prebuilt libraries that are used by the
    // app's library defined in CMakeLists.txt via an IMPORTED target.
    jniLibs.setSrcDirs(listOf("libs"))
  }
}

使用 Android Gradle Plugin 4.0,上述配置不再必要,并且会导致构建失败

* What went wrong:
Execution failed for task ':app:mergeDebugNativeLibs'.
  > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
    > More than one file was found with OS independent path 'lib/x86/libprebuilt.so'

外部原生构建现在会自动打包这些库,因此使用 jniLibs 显式打包库会导致重复。为避免构建错误,请将预构建库移至 jniLibs 之外的位置,或从您的 build.gradle 文件中移除 jniLibs 配置。

已知问题

本节介绍 Android Gradle plugin 4.0.0 中存在的已知问题。

Gradle worker 机制中的竞态条件

Android Gradle plugin 4.0 中的更改可能在与 Gradle 6.3 或更低版本一起使用 &endash;&endash;no&endash;daemon 运行时触发 Gradle 中的竞态条件,导致构建完成后卡住。

此问题将在 Gradle 6.4 中修复。