虽然你应该尽可能建立一个单一的APK来支持所有的目标设备,这可能会导致用一个非常大的APK处理支持多个屏幕密度或应用二进制接口(ABIs)。 减少APK大小的一种方法是创建多个APK,其中包含特定屏幕密度或ABI的文件。
Gradle使用APK拆分来创建单独的APK,这些APK仅包含特定于每个密度或ABI的代码和资源。 本页介绍如何配置构建来完成APK拆分。 如果您需要创建不基于屏幕密度或ABI的不同版本的应用程序,您可以改用构建变体。
APK拆分配置
要启用APK拆分,请在模块级build.gradle文件中添加一个splits {}
块。 在split {}
块中,提供一个density {}
指定Gradle应如何生成每个密度的APK,或者一个 abi {}
指定Gradle应如何生成每个ABI的APK。 您可以提供密度和ABI块,构建系统将为每个密度和ABI组合创建一个拆分APK。
配置APK拆分的密度
要为不同的屏幕密度创建单独的APK,请在split {}
块中添加density {}
块。 在您的density {}
块中,提供所需的屏幕密度和兼容的屏幕尺寸的列表。 只有在每个APK的清单中需要特定的<compatible-screens>
元素时,才能使用兼容的屏幕尺寸列表。
以下Gradle DSL选项用于配置密度APK拆分:
enable
如果将此元素设置为true,Gradle会根据您定义的屏幕密度生成APK分割。 默认值为false。
exclude
指定一个逗号分隔的密度列表,Gradle不应为其生成单独的APK。 如果您想为大多数密度生成APK,但需要排除应用不支持的几个密度,请使用exclude。
reset()
清除默认的屏幕密度列表。 仅当与include
元素组合使用时才能指定要添加的密度。 以下代码片段将密度列表设置为ldpi
和xxhdpi
,方法是调用reset()
清除列表,然后使用include
:
reset() // clear the default list from all densities to no densities
include "ldpi", "xxhdpi" // specify the two densities we want to generate APKs for
- 1
- 2
include
指定Gradle应生成APK的密度的逗号分隔列表。 只能与reset()结合使用以指定密度的精确列表。
compatibleScreens
指定兼容的屏幕尺寸用逗号分隔的列表。 这将在每个拆分APK的清单中注入匹配的<compatible-screens>
节点。 这个可选设置提供了在同一个build.gradle
部分管理屏幕密度和屏幕大小的方便方法,但是使用<compatible-screens>
将限制您的应用程序将使用的设备类型。 有关支持不同屏幕大小的其他方法,请参阅支持多个屏幕。
因为基于屏幕密度的拆分的每个APK都包含一个<compatible-screens>
标签,其中包含APK支持的屏幕类型的具体限制,即使您发布了多个APK,一些新设备也不会与您的多个APK过滤器匹配。 因此,Gradle总是生成一个额外的通用APK,包含所有屏幕密度的资源,并且不包括<compatible-screens>
标记。 您应该发布此通用APK以及拆分APK,以便为与APK不匹配的设备提供后备方案(使用<compatible-screens>
标记)。
以下示例为支持的屏幕范围中列出的每个屏幕密度生成单独的APK,除了ldpi
,xxhdpi
和xxxhdpi
。 这是通过使用exclude
从所有密度的默认列表中删除三个密度来完成的:
android {
...
splits {
// Configures screen density split settings
density {
// Enables density APK splits
enable true
// Specifies a list of screen densities Gradle should not create APK splits for
exclude "ldpi", "xxhdpi", "xxxhdpi"
// Specifies a list of compatible screen size settings for the manifest
compatibleScreens 'small', 'normal', 'large', 'xlarge'
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
有关密度名称和屏幕尺寸名称的列表,请参阅如何支持多屏幕。 有关将应用程序分发到特定屏幕类型和设备的详细信息,请参阅分发到特定屏幕。
配置APK拆分的ABI
要为不同的ABI创建单独的APK,请在您的split {}
块中添加一个abi {}
块。 在您的abi {}
块中,提供所需ABI的列表。
以下Gradle DSL选项用于配置每ABI APK拆分:
enable
如果将此元素设置为true,Gradle会根据您定义的ABI生成APK拆分。 默认值为false
exclude
指定一个逗号分隔的ABI列表,Gradle不应为其生成单独的APK。 如果您想为大多数ABI生成APK,但需要排除应用程序不支持的几个ABI,请使用exclude
。
reset()
清除ABI的默认列表。 仅当与include元素组合使用时才指定要添加的ABI。 以下代码片段通过调用reset()将ABI列表设置为x86
和mips
,以清除列表,然后使用include
:
reset() // clear the default list from all ABIs to no ABIs
include "x86", "mips" // specify the two ABIs we want to generate APKs for
- 1
- 2
include
指定Gradle应为其生成APK的ABI的逗号分隔列表。 只能与reset()结合使用以指定ABI的精确列表。
universalApk
如果为true,Gradle会生成一个通用APK以及拆分APK。 通用APK包含单个APK中所有ABI的代码和资源。 默认值为false。 请注意,此选项仅适用于ABI APK拆分。 密度APK分裂总是生成一个通用的APK,包含所有屏幕密度的代码和资源。
以下示例为每个ABI生成单独的APK:x86,armeabi-v7a和mips。 这是通过使用reset()开始一个空列表的ABI,然后是包含三个ABI列表,每个都将获得一个APK:
android {
...
splits {
// Configures screen ABI split settings
abi {
// Enable ABI APK splits
enable true
// By default all ABIs are included, so use reset() and include to specify that we only
// want APKs for x86, armeabi-v7a, and mips
// Resets the list of ABIs that Gradle should create APKs for to none
reset()
// Specifies a list of ABIs that Gradle should create APKs for
include "x86", "armeabi-v7a", "mips"
// Specify that we do not want to also generate a universal APK that includes all ABIs
universalApk false
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
有关支持的ABI的列表,请参阅支持的ABI。
配置APK拆分的版本控制
默认情况下,当Gradle生成APK拆分时,每个APK将具有相同的版本信息,如模块级build.gradle文件中指定的。 由于Google Play商店不允许具有相同版本信息的同一应用程序使用多个APK,因此您需要确保每个split APK都有自己独特的versionCode
,然后才能上传到Play商店。
您可以配置模块级build.gradle
文件以覆盖每个拆分APK的versionCode
。 为APK拆分中使用的每个ABI和密度分配唯一的数值,然后使用将·defaultConfig.versionCode·与分配给密度或ABI的数值组合的值覆盖输出版本代码。
以下示例创建一个映射,为每个用于APK拆分的ABI分配唯一的数值。 使用此映射,创建一个每拆分APK版本代码,其将映射的ABI值与defaultConfig.versionCode
组合。 在此示例中,x86 ABI的split APK将获得304的versionCode
。如果defaultConfig.versionCode
重复为5,Gradle将为x86拆分APK分配一个versionCode
为305。
android {
...
defaultConfig {
...
versionCode 4
}
splits {
...
}
}
// map for the version code that gives each ABI a value
ext.versionCodes = ['armeabi-v7a':1, mips:2, x86:3]
// For each APK output variant, override versionCode with a combination of
// ABI APK value * 100 + defaultConfig.versionCode
android.applicationVariants.all { variant ->
// assign different version code for each output
variant.outputs.each { output ->
output.versionCodeOverride =
project.versionCodes.get(output.getFilter(OutputFile.ABI)) * 100
+ android.defaultConfig.versionCode
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
有关备用版本代码方案的更多示例,请参阅分配版本代码。
构建APK拆分
配置模块级build.gradle
文件以构建APK拆分后,请在Project 窗格单击Build > Build APK为当前选定的模块构建所有APK。 Gradle为每个密度或ABI创建APK在项目的build/outputs/apk/
目录下。
Gradle为每个配置的密度或ABI拆分构建一个APK。 如果您为密度和ABI启用了分割,Gradle将为每个密度和ABI组合创建一个APK。 例如,以下build.gradle
代码段允许构建mdpi和hdpi密度的APK拆分,以及x86和mips ABI:
...
splits {
density {
enable true
reset()
include "mdpi", "hdpi"
}
abi {
enable true
reset()
include "x86", "mips"
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
示例配置的输出将包括以下4个拆分APK:
* app-hdpiX86-release.apk
: 仅包含hdpi density和x86 ABI的代码和资源。
* app-hdpiMips-release.apk
: 仅包含hdpi密度和mips ABI的代码和资源。
* app-mdpiX86-release.apk
: 仅包含mdpi密度和x86 ABI的代码和资源。
* app-mdpiMips-release.apk
: 仅包含mdpi密度和mips ABI的代码和资源。
根据您如何配置APK拆分,Gradle还将生成一个通用APK,包含所有密度或ABI的代码和资源。 对于密度APK的拆分,Gradle将始终生成一个通用APK,包括所有密度的代码和资源,除了每个密度的APK。 对于ABI拆分,如果在build.gradle
文件中的splits {}
块的abi部分中指定universalApk true
,Gradle只会生成包含所有ABI的代码和资源的APK。
APK文件名格式
对于APK拆分,Gradle使用APK文件名使用以下方案: modulename-screendensityABI-buildvariant.apk
方案组件是:
modulename
指定正在构建的模块名称。
screendensity
如果启用屏幕密度APK拆分,则指定APK的屏幕密度,例如“mdpi”。
ABI
如果启用ABI APK拆分,则指定APK的ABI,例如“x86”。 如果屏幕密度和ABI APK拆分都启用,Gradle将密度名称与ABI名称连接,例如“mdpiX86”。 如果为ABI APK分裂启用universalApk
,Gradle使用“通用”作为通用APK文件名的ABI部分。
buildvariant
指定正在构建的构建变量,例如“debug”。
例如,对于mdpi屏幕密度启用APK拆分的“myApp”的调试版本将使用APK文件名myApp-mdpi-debug.apk
。 发布版本的“myApp”的APK分裂已启用mdpi屏幕密度和x86 ABI将使用APK文件名myApp-mdpiX86-release.apk
。