Reduce your app size
Small app size is directly related to download success, particularly in emerging markets with poor network device connections or low network speeds. This can result in lower app usage rates, which in turn lowers the scope and reach of your audience.1
The main ways to reduce the size of app are:
- Upload your app with Android App Bundles
- Reduce resource count and size
- Reduce native and Java code
- Re-evaluate feature and translation
Upload your app with Android App Bundles
Upload your app as an Android App Bundle to immediately save app size when you publish to Google Play. Android App Bundle is an upload format that includes all your app’s compiled code and resources but defers APK generation and signing to Google Play.
Google Play’s app serving model then uses your app bundle to generate and serve optimized APKs for each user’s device configuration so that they download only the code and resources they need to run your app. You don’t have to build, sign, and manage multiple APKs to support different devices, and users get smaller, more optimized downloads.
Reduce resource count and size
The size of your APK has an impact on how fast your app loads, how much memory it uses, and how much power it consumes. You can make your APK smaller by reducing the number and size of the resources it contains. In particular, you can remove resources that your app no longer uses, and you can use scalable Drawable
objects in place of image files.
Remove unused resources
The lint
tool—a static code analyzer included in Android Studio—detects resources in your res/
folder that your code doesn’t reference. When the lint
tool discovers a potentially unused resource in your project, it prints a message like the following example:
res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
to be unused [UnusedResources]
Libraries that you add to your code might include unused resources. Gradle can automatically remove resources on your behalf if you enable shrinkResources
in your app’s build.gradle.kts
file:
android {
// Other settings.
buildTypes {
getByName("release") {
minifyEnabled = true
shrinkResources = true
proguardFiles(getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro")
}
}
}
To use shrinkResources
, enable code shrinking. During the build process, R8 first removes unused code. Then, the Android Gradle plugin removes the unused resources.
Support only specific densities
Android supports different screen densities, such as the following:
ldpi
;mdpi
;tvdpi
;hdpi
;xhdpi
;xxhdpi
;xxxhdpi
.
Although Android supports the preceding densities, you don’t need to export your rasterized assets to each density.
If you know that only a small percentage of your users have devices with specific densities, consider whether you need to bundle those densities into your app. If you don’t include resources for a specific screen density, Android automatically scales existing resources originally designed for other screen densities.
If your app needs only scaled images, you can save even more space by having a single variant of an image in drawable-nodpi/
. We recommend you include at least an xxhdpi
image variant in your app.
Use drawable objects
Some images don’t require a static image resource. The framework can dynamically draw the image at runtime instead. Drawable
objects—or <shape>
in XML — can take up a tiny amount of space in your APK. In addition, XML Drawable
objects produce monochromatic images compliant with Material Design guidelines.
Reuse resources
You can include a separate resource for variations of an image, such as tinted, shaded, or rotated versions of the same image. However, we recommend that you reuse the same set of resources and customizing them as needed at runtime.
Android provides several utilities to change the color of an asset, either using the android:tint
and tintMode
attributes.
You can also omit resources that are only a rotated equivalent of another resource. The following code snippet provides an example of turning a “thumb up” into a “thumb down” by pivoting at the middle of the image and rotating it 180 degrees:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_thumb_up"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="180" />
Compress PNG and JPEG files
You can reduce PNG file sizes without losing image quality using tools like pngcrush, pngquant, or zopflipng. All of these tools can reduce PNG file size while preserving the perceptive image quality.
The pngcrush
tool is particularly effective. This tool iterates over PNG filters and zlib (Deflate) parameters, using each combination of filters and parameters to compress the image. It then chooses the configuration that yields the smallest compressed output.
To compress JPEG files, you can use tools like packJPG and guetzli.
Use WebP file format
Instead of using PNG or JPEG files, you can also use the WebP file format for your images. The WebP format provides lossy compression and transparency, like JPG and PNG, and it can provide better compression than either JPEG or PNG.
You can convert existing BMP, JPG, PNG or static GIF images to WebP format using Android Studio. For more information, see Create WebP images.
Use Downloadable Fonts
Since most programs on the Play Store share the same fonts, the App package already includes many of them. Duplication occurs when a user runs multiple apps with the same fonts on the same device. In response to the issue, Google added Downloadable fonts to its Support collection. APIs can now simply request typefaces instead of bundling files.
Reduce native and Java code
You can use the following methods to reduce the size of the Java and native codebase in your app:
- Remove unnecessary generated code. Make sure to understand the footprint of any code which is automatically generated. For example, many protocol buffer tools generate an excessive number of methods and classes, which can double or triple the size of your app;
- Avoid enumerations. A single enum can add about 1.0 to 1.4 KB to your app’s
classes.dex
file. These additions can quickly accumulate for complex systems or shared libraries. If possible, consider using the@IntDef
annotation and code shrinking to strip enumerations out and convert them to integers. This type conversion preserves all of the type safety benefits of enums; - Reduce the size of native binaries. If your app uses native code and the Android NDK, you can also reduce the size of the release version of your app by optimizing your code. Two useful techniques are removing debug symbols and not extracting native libraries;
- Remove debug symbols. Using debug symbols makes sense if your app is in development and still requires debugging. Use the
arm-eabi-strip
tool provided in the Android NDK to remove unnecessary debug symbols from native libraries. Afterwards, you can compile your release build. - Avoid extracting native libraries. When building the release version of your app, package uncompressed
.so
files in the APK by settinguseLegacyPackaging
tofalse
in your app’sbuild.gradle.kts
file. Disabling this flag preventsPackageManager
from copying.so
files from the APK to the filesystem during installation. This method makes updates of your app smaller.
Re-evaluate feature and translation
Re-evaluate infrequently used features
Specifically optimize for Android (Go edition) by disabling features that have low daily active user (DAU) metrics. Examples of this include removing complex animations, large GIF files, or any other aesthetic additions not necessary for app success.
Utilize dynamic delivery
Play Feature Delivery uses advanced capabilities of app bundles, allowing certain features of your app to be delivered conditionally or downloaded on demand. You can use feature modules for custom delivery. A unique benefit of feature modules is the ability to customize how and when different features of your app are downloaded onto devices running Android 5.0 (API level 21) or higher.
Reduce translatable string size
You can use the Android Gradle resConfigs
property to remove alternative resource files that your app doesn’t need. If you’re using a library that includes language resources (such as AppCompat or Google Play Services), then your app includes all translated language strings for library messages, regardless of app translation. If you’d like to keep only the languages that your app officially supports, you can specify those languages using the resConfig
property. Any resources for languages not specified are removed.
To limit your language resources to just English and French, you can edit defaultConfig
as shown below:
android {
defaultConfig {
...
resConfigs "en", "fr"
}
}
Use selective translation
If a given string isn’t visible in the app’s UI, then you don’t have to translate it. Strings for the purpose of debugging, exception messages, or URLs should be string literals in code, not resources.
For example, don’t bother translating URLs:
<string name="car_frx_device_incompatible_sol_message">
This device doesn\'t support Android Auto.\n
<a href="https://support.google.com/androidauto/answer/6395843">Learn more</a>
</string>
You may recognize <
and >
, as these are escape characters for <
and >
. They’re needed here because if you were to put an <a>
tag inside of a <string>
tag, then the Android resource compiler drops them since it doesn’t recognize the tag. However, this means that you’re translating the HTML tags and the URL to 78 languages. Instead, you can remove the HTML:
<string name="car_frx_device_incompatible_sol_message">
This device doesn\'t support Android Auto.
</string>
Links
8 Ways to Reduce Android App Size During Development Phase?
Further Reading
8 Best Ways to Reduce Android App Size
Minimizing APK Size: Techniques for Shrinking Android App Size
Next Questions
What do you know about App Bundles?
What do you know about Play Feature Delivery?
What do you know about downloadable fonts?