配置您的版本

Android 构建系统会编译应用资源和源代码,然后将它们打包到 APK 中,供您测试、部署、签名和分发。Android Studio 会使用高级构建工具包 Gradle 来自动执行和管理构建流程,同时也允许您定义灵活的自定义版本配置。每个版本配置均可定义自己的一组代码和资源,同时重复利用应用各个版本的共用部分。Android Plugin for Gradle 可与该构建工具包搭配使用,来提供专用于构建和测试 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) 的工具和流程。构建流程非常灵活,因此了解它的一些底层工作原理会很有帮助。

图 1. 典型 Android 应用模块的构建流程。

如图 1 所示,典型 Android 应用模块的构建流程通常按照以下步骤执行:

  1. 编译器将您的源代码转换成 DEX 文件(Dalvik 可执行文件,其中包括在 Android 设备上运行的字节码),并将其他所有内容转换成编译后的资源。
  2. APK 打包器将 DEX 文件和编译后的资源合并到一个 APK 中。不过,在将应用安装并部署到 Android 设备之前,必须先为 APK 签名。
  3. APK 打包器使用调试或发布密钥库为 APK 签名:
    1. 如果您构建的是调试版应用(即专用于测试和分析的应用),则打包器会使用调试密钥库为应用签名。Android Studio 会自动使用调试密钥库配置新项目。
    2. 如果您构建的是打算对外发布的发布版应用,则打包器会使用发布密钥库为应用签名。要创建发布密钥库,请参阅在 Android Studio 中为应用签名
  4. 在生成最终 APK 之前,打包器会使用 zipalign 工具对应用进行优化,以减少其在设备上运行时所占用的内存。

构建流程结束时,您将获得应用的调试版 APK 或发布版 APK,以用于部署、测试或发布给外部用户。

自定义版本配置

Gradle 和 Android 插件可帮助您完成以下方面的版本配置:

版本类型
版本类型定义 Gradle 在构建和打包应用时使用的某些属性,通常针对开发流程的不同阶段进行配置。例如,调试版本类型支持调试选项,并使用调试密钥为 APK 签名;而发布版本类型则会缩减 APK、对 APK 进行混淆处理,并使用发布密钥为 APK 签名以进行分发。要构建应用,您必须至少定义一个版本类型。Android Studio 默认会创建调试和发布两个版本类型。要开始为应用自定义打包设置,请了解如何配置版本类型
产品变种
产品变种代表您会向用户发布的应用的不同版本,如应用的免费版和付费版。您可以自定义产品变种来使用不同的代码和资源,同时共享和重复利用各版应用的共用部分。产品变种是可选的,您必须手动创建。要开始创建应用的不同版本,请了解如何配置产品变种
版本变体
版本变体是版本类型与产品变种的交叉产物,也是 Gradle 用来构建应用的配置。利用版本变体,您可以在开发期间构建产品变种的调试版本,或者构建产品变种的已签名发布版本以供分发。虽然您无法直接配置版本变体,但可以配置组成它们的版本类型和产品变种。创建额外的版本类型或产品变种也会创建额外的版本变体。要了解如何创建和管理版本变体,请参阅配置版本变体概览。
清单条目
您可以在版本变体配置中为清单文件的某些属性指定值。这些版本值会替换清单文件中的现有值。如果您要为模块生成多个 APK,让每一个 APK 文件都具有不同的应用名称、最低 SDK 版本或目标 SDK 版本,便可运用这一技巧。当存在多个清单时,Gradle 会合并清单设置
依赖项
构建系统会管理来自本地文件系统以及来自远程代码库的项目依赖项。这样一来,您就不必手动搜索、下载依赖项的二进制文件包以及将它们复制到项目目录中。要了解详情,请参阅添加构建依赖项
签名
构建系统允许您在版本配置过程中指定签名设置,并且可以在构建过程中自动为 APK 签名。构建系统通过已知凭据使用默认密钥和证书为调试版本签名,以避免在构建时提示输入密码。除非您为发布版本明确定义签名配置,否则,构建系统将不会为此版本签名。如果您没有发布密钥,可以按为应用签名中所述生成一个。
代码和资源缩减
构建系统允许您为每个版本变体指定不同的 ProGuard 规则文件。在构建应用时,构建系统会应用一组适当的规则来使用其内置的缩减工具(如 R8)缩减您的代码和资源
多 APK 支持
构建系统支持您自动构建不同的 APK,并使每个 APK 只包含特定屏幕密度或应用二进制接口 (ABI) 所需的代码和资源。 如需了解详情,请参阅构建多个 APK

版本配置文件

创建自定义版本配置需要您对一个或多个版本配置文件(即 build.gradle 文件)做出更改。这些纯文本文件使用领域特定语言 (DSL) 以 Groovy 来描述和操纵版本逻辑,其中 Groovy 是一种适用于 Java 虚拟机 (JVM) 的动态语言。您无需了解 Groovy 便可开始配置版本,因为 Android Plugin for Gradle 引入了您需要的大多数 DSL 元素。如需详细了解 Android 插件 DSL,请参阅 DSL 参考文档

如图 2 所示,开始新项目时,Android Studio 会自动为您创建其中的部分文件,并为其填充合理的默认值。

图 2. Android 应用模块的默认项目结构。

有一些 Gradle 版本配置文件是 Android 应用的标准项目结构的组成部分。您必须了解其中每个文件的范围和用途及其应定义的基础 DSL 元素,才能着手配置版本。

Gradle 设置文件

settings.gradle 文件位于项目的根目录下,用于指示 Gradle 在构建应用时应将哪些模块包含在内。对大多数项目而言,该文件很简单,只包含以下内容:

    include ‘:app’
    

不过,多模块项目需要指定应包含在最终版本中的每个模块。

顶层版本文件

顶层 build.gradle 文件位于项目的根目录下,用于定义适用于项目中所有模块的版本配置。默认情况下,顶层版本文件使用 buildscript 代码块来定义项目中所有模块共用的 Gradle 代码库和依赖项。以下代码示例说明了创建新项目后可在顶层 build.gradle 文件中找到的默认设置和 DSL 元素。

    /**
     * The buildscript block is where you configure the repositories and
     * dependencies for Gradle itself—meaning, you should not include dependencies
     * for your modules here. For example, this block includes the Android plugin for
     * Gradle as a dependency because it provides the additional instructions Gradle
     * needs to build Android app modules.
     */

    buildscript {

        /**
         * The repositories block configures the repositories Gradle uses to
         * search or download the 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
         * JCenter as the repository Gradle should use to look for its dependencies.
         *
         * New projects created using Android Studio 3.0 and higher also include
         * Google's Maven repository.
         */

        repositories {
            google()
            jcenter()
        }

        /**
         * The dependencies block configures the dependencies Gradle needs to use
         * to build your project. The following line adds Android plugin for Gradle
         * version 3.5.2 as a classpath dependency.
         */

        dependencies {
            classpath 'com.android.tools.build:gradle:3.5.2'
        }
    }

    /**
     * The allprojects block is where you configure the repositories and
     * dependencies used by all modules in your project, such as third-party plugins
     * or libraries. However, you should configure module-specific dependencies in
     * each module-level build.gradle file. For new projects, Android Studio
     * includes JCenter and Google's Maven repository by default, but it does not
     * configure any dependencies (unless you select a template that requires some).
     */

    allprojects {
       repositories {
           google()
           jcenter()
       }
    }
    

配置项目全局属性

对于包含多个模块的 Android 项目,可能有必要在项目层级定义某些属性并在所有模块之间共享这些属性。为此,您可以将额外的属性添加到顶层 build.gradle 文件内的 ext 代码块中。

    buildscript {...}

    allprojects {...}

    // This block encapsulates custom properties and makes them available to all
    // modules in the project.
    ext {
        // The following are only a few examples of the types of properties you can define.
        compileSdkVersion = 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"
        ...
    }
    ...
    

要从同一项目中的模块访问这些属性,请在该模块的 build.gradle 文件(您可以在下一部分中详细了解此文件)中使用以下语法。

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

注意:虽然 Gradle 可让您在模块级别定义项目全局属性,但您应避免这样做,因为这样会导致共享这些属性的模块进行耦合。模块耦合使得以后将模块作为独立项目导出更加困难,并实际妨碍 Gradle 利用并行项目执行来加快多模块构建。

模块级版本文件

模块级 build.gradle 文件位于每个 project/module/ 目录下,用于为其所在的特定模块配置版本设置。您可以通过配置这些版本设置来提供自定义打包选项(如额外的版本类型和产品变种),以及替换 main/ 应用清单或顶层 build.gradle 文件中的设置。

以下 Android 应用模块 build.gradle 文件示例简要说明了您应该了解的一些基础 DSL 元素和设置。

    /**
     * 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.
     */

    apply plugin: 'com.android.application'

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

    android {

      /**
       * 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

      /**
       * 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 "29.0.0"

      /**
       * 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 {

        /**
         * applicationId uniquely identifies the package for publishing.
         * However, your source code should still reference the package name
         * defined by the package attribute in the main/AndroidManifest.xml file.
         */

        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 splits block is where you can configure different APK builds that
       * each contain only code and resources for a supported screen density or
       * ABI. You'll also need to configure your build so that each APK has a
       * different versionCode.
       */

      splits {
        // Settings to build multiple APKs based on screen density.
        density {

          // Enable or disable building multiple APKs.
          enable false

          // Exclude these densities when building multiple APKs.
          exclude "ldpi", "tvdpi", "xxxhdpi", "400dpi", "560dpi"
        }
      }
    }

    /**
     * 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'])
    }
    

Gradle 属性文件

Gradle 还包含两个属性文件,它们位于项目的根目录下,可用于指定 Gradle 构建工具包本身的设置:

gradle.properties
您可以在其中配置项目全局 Gradle 设置,如 Gradle 守护进程的最大堆大小。如需了解详情,请参阅构建环境
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 便可使用专用于您试图构建的版本变体的文件,同时重复利用与应用的其他版本共用的 Activity、应用逻辑和资源。在合并多个清单时,Gradle 会使用相同的优先级顺序,这样每个版本变体都能在最终清单中定义不同的组件或权限。要详细了解如何创建自定义源集,请参阅创建版本变体的源集