为配置 APK 设置编译环境

您可以为配置 APK 设置编译环境,从而缩减您的应用在每个用户设备上的 APK 大小。这会将应用的 DEX 代码以及与设备无关的资源放在一个 APK 中,并将每组依赖于设备的原生代码和资源放在单独的 APK 中。然后,设备只会请求运行您的应用所需的 APK。这样,您就可以在创建的 APK 中包含适用于特定屏幕密度、ABI 和/或语言的文件,从而缩减应用的下载大小。

配置 APK 类似于多个 APK,但有一些重要的区别:

  • 目前,多个 APK 仅适用于安装版应用,而配置 APK 则只适用于免安装应用。
  • 对于多个 APK,会为每个属性组合构建一个 APK。而对于配置 APK,则会有一个基本 APK,其中包含与设备无关的 DEX 代码,还有一个 APK 用于各个可变维度的每个值(即每个受支持的语言、密度或 ABI 都有一个对应的 APK)。举例来说,假设因密度和语言而异的某个应用支持四种密度和三种语言。对于多个 APK,开发者会上传 3 * 4 = 12 个 APK。而对于配置 APK,他们则会上传 1(基本)+ 3 + 4 = 8 个 APK。对于多个 APK,任何特定设备都只会获得一个 APK。对于配置 APK,设备会获得一个基本 APK,另外可能还会获得每个受支持维度(目前为语言、密度和 ABI)的一个或多个资源 APK。
  • 借助多个 APK,您可以使用版本代码从特定设备的多个兼容 APK 中进行选择。配置 APK 则不使用开发者指定的排序。排序取决于可用 APK 的定位。
  • 配置 APK 支持新的定位维度 language。多个 APK 则不支持。

前提条件

在为配置 APK设置编译环境之前,请查看以下步骤,确保您的编译环境已准备就绪,并验证您在 Android Studio 中是否具备所需的工具配置:

  • 将您的免安装应用模块的最低 SDK 版本设置为 21 或更高版本
  • 使用 Android Studio 3.0 或更高版本

为配置 APK 设置编译环境

要根据语言为您的配置 APK 设置编译环境,请在功能模块的 splits 块中添加语言块,并在 android 块中指定 generatePureSplits = true。有关配置 splits 块的详情,请参阅针对多个 APK 配置编译

    android {
      ...
      generatePureSplits = true
      splits {
        abi {
          enable = true
        }
        density {
          enable = true
        }
        language {
          enable = true
          include "es-rMX", "zh", "en"
        }
      }
    }
    

语言值采用提供备用资源中所述的格式。

传送配置 APK

与使用多个 APK 不同,开发者不会为多个等效配置 APK 定义排序。那么,Play 如何决定要传送哪个 APK?

对于 ABI,Play 会按照对所有设备都一样的固定排序从兼容的 APK 中进行选择。该排序为 x86_64x86mips64mipsarm64-v8aarmeabi-v7aarmeabi。举例来说,如果设备同时支持 x86armeabi-v7a,并且两者都有相应的 APK,则会传送 x86 APK(以及基本 APK)。

对于密度,Play 会在可用的 APK 中选择最接近设备密度的 APK。

按语言选择 APK 更为复杂。

关于语言定位的特殊问题

有人可能认为 Play 会尝试完全匹配用户的语言区域。如果是 en-GB,则可能传送定向到 en-GB 的 APK(如果可用),否则回退到 en。这种方法存在两个问题:

  1. 不要求配置 APK 必须包含每个字符串的翻译,就像 strings.xml 文件没有这种要求一样。可以接受为仅有的一个字符串或少量字符串添加语言(甚至很常见)。例如,en/strings.xml 可能包含“car”和“truck”,而 en-rGB/strings.xml 则可能只包含“lorry”。因此,正如任何设备所必需的的翻译集可能位于多个 strings.xml 文件中一样,这些文件可能包含在多个配置 APK 中。
  2. Android 设备具有变化多样的回退图表。Android 版本可以更改回退图表(请参阅语言和语言区域指南)。此外,原始设备制造商 (OEM) 还会自定义回退顺序(例如,“zh” 指的是 “zh-TW” 还是 “zh-CN” 取决于 OEM)。Play 并不总是知道发出请求的设备使用了什么回退顺序。

为了解决这些问题,Play 会传送满足下述条件的所有配置 APK:它们都定位到语言子标签(短划线前面的部分)与用户所选语言区域相匹配的语言。这依赖于一个观察现象,即回退算法通常不会跨语言回退。示例如下:

用户的语言区域为 de-CH
可用的 APK 为 dede-CHde-ATfr
Play 传送 dede-CHde-AT,但不传送 fr

在有些情况下,尽管语言子标签不匹配,例如 fil/tag,也应将语言组合起来,Play 也会处理这种熟知的情况。

Play 会在传送时完成组合操作,无需开发者执行任何操作。

问题排查和常见问题解答

  • Gradle 未生成配置 APK,而是显示了以下消息
        Variant ..., MinSdkVersion 18 is too low (<21) to support pure splits,
        reverting to full APKs
        

    在免安装应用模块的 build.gradle 文件中指定 minSdkVersion = 21

  • Gradle 插件显示以下消息:
        > Configure project :base
        Pure splits are not supported by PlayStore yet.
        

    这是一个已知问题。请忽略此消息。

  • 配置 APK 对 4MB 的限制有何影响?

    功能大小的计算方式是以下三项之和:功能 APK 大小,基本功能 APK 大小以及可能传送到设备的最大配置 APK 集。例如,如果某个功能的基本 APK 有 3 个语言 APK 和 2 个密度 APK,功能 APK 有 2 个密度 APK,那么功能 APK 大小加上基本 APK 大小,再加上基本 APK 的最大语言和最大密度 APK,以及功能 APK 的最大密度 APK,即得出最后的功能大小。

已知问题

  • 对于某些增量编译,Gradle 无法编译 ABI APK(https://issuetracker.google.com/69680755)。这个问题可以通过清理并重新编译来解决。
  • 目前,编译工具无法创建多维配置 APK。例如,针对采用法语的 xhdpi 设备,某个项目可能在 res/drawable-fr-xhdpi 中包含一项资源,但 Gradle 无法将此类资源放入配置 APK 中。任何此类资源都会放入基本或功能 APK 中。