In Chapter 4, Creating Build Variants, we looked at several ways to create multiple versions of the same app, using build types and product flavors. However, in some cases, it might be easier to use a more specific technique, such as APK splits.
Build variants can be seen as separate entities, that can each have their own code, resources, and manifest file. APK splits, on the other hand, only impact the packaging of an app. The compilation, shrinking, obfuscation, and so on are still shared. This mechanism allows you to split APKs based on either density or application binary interface (ABI).
You can configure splits by defining a splits
block inside the android
configuration block. To configure density splits, create a density
block inside the splits
block. If you want to set up ABI splits, use an abi
block.
If you enable density splits, Gradle creates a separate APK for each density. You can manually exclude certain densities if you do not need them, to speed up the build process. This example shows how to enable density splits and exclude devices with low density:
android { splits { density { enable true exclude 'ldpi', 'mdpi' compatibleScreens 'normal', 'large', 'xlarge' } } }
If you only support a few densities, you can use include
to create a whitelist of densities. To use include, you first need to use the reset()
property, which resets the list of included densities to an empty string.
The compatibleScreens
property in the preceding snippet is optional, and injects a matching node in the manifest file. The configuration in the example is for an app that supports normal to extra large screens, excluding devices with small screens.
Splitting APKs based on the ABI works in the same way, and all of the properties are the same as the properties for density splits, except for compatibleScreens
. ABI splits have nothing to do with screen size, so there is no property called compatibleScreens
.
The result of executing a build after configuring the density splits is that Gradle now creates one universal APK and several density-specific APKs. This means you will end up with a collection of APKs like this:
app-hdpi-release.apk app-universal-release.apk app-xhdpi-release.apk app-xxhdpi-release.apk app-xxxhdpi-release.apk
There is one caveat to using APK splits, though. If you want to push multiple APKs to Google Play, you will need to make sure every APK has a different version code. This means that each split should have a unique version code. Luckily, by now you are able to do this in Gradle by looking at the applicationVariants
property.
The following snippet comes straight from the Android plugin for Gradle documentation, and shows how to generate different version codes for each APK:
ext.versionCodes = ['armeabi-v7a':1, mips:2, x86:3] import com.android.build.OutputFile android.applicationVariants.all { variant -> // assign different version code for each output variant.outputs.each { output -> output.versionCodeOverride = project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) * 1000000 + android.defaultConfig.versionCode } }
This little snippet checks which ABI is used on a build variant, and then applies a multiplier to the version code to make sure each variant has a unique version code.