Optimizing APK size in Android

Sonika Srivastava
CodeX
Published in
7 min readJan 28, 2023

Most users do not prefer to download apps which are huge in size. Even after downloading, there is a huge risk that users may uninstall the app due to space constraints on their devices. Thus optimizing the APK size is something which all developers have to keep in mind.

Many enterprise Apps or Apps with complex use cases such as streaming applications, image filter applications etc tend to increase in size due to the usage of heavy 3rd party libraries/SDKs. In such cases, it becomes even more important to look for ways to reduce the APK size as much as possible. The following practices can help optimize the APK Size.

1. App Bundle

Android App bundle is a publishing format which defers APK generation and signing to Google Play. Google Play generates optimized APKs for each device configuration so that only the resources needed for specific devices are downloaded to run your app. Thus this significantly reduces the app size for the users.

Let’s say we have hdpi,xhdpi,xxhdpi resources in our app and if the target device is xhdpi device, only xhdpi resources will be installed on the device. Similarly, native libraries will be downloaded based on the device e.g x86, arm etc. This significantly helps in saving the memory in the device.

Ideally, switching from APK to App Bundles should not be difficult if we have already organized our app’s source code and resources according to established conventions.

More information on organizing resources can be obtained here:

App Bundle can be generated using the “Build Signed Android App Bundle” option in Android Studio.

App Bundle is also now a Google mandate for new applications.

2. Dynamic App Module

This uses the advanced capabilities of App Bundles to allow certain features of your app to be delivered conditionally or downloaded on demand. These features need to be separated from the base app into feature modules.

This greatly helps in reducing the initial download size of the app. Developers can configure certain features to be downloaded on demand or based on the device’s capabilities e.g. to support Augmented Reality features.

The android platform can treat multiple installed split APKs as a single app. The benefit of split APKs is the ability to break up a monolithic APK into smaller, discrete packages that are installed on a user’s device as required

The base APK contains code and resources that all other split APKs can access and provides the basic functionality for your app. When a user requests to download your app, this APK is downloaded and installed first. That’s because only the base APK’s manifest contains a full declaration of your app’s services, content-providers, permissions, platform version requirements, and dependencies on system features. Dynamic Feature APK contains code and resources for a feature of your app that is not required when your app is first installed. That is, using the Play Core Library, dynamic APKs may be installed on demand after the base APK is installed on the device to provide additional functionality to the user.

Dynamic Feature Module can be created using Android Studio

Select File > New > New Module from the menu bar. In the Create New Module dialog, select Dynamic Feature Module

After Dynamic Module is created, Android studio applies the following plugin

plugins {

id ‘com.android.dynamic-feature’

}

It also makes it visible to the base module by adding dynamic feature configuration in the base module’s build.gradle file.

dynamicFeatures = [“:dynamic_feature”, “:dynamic_feature2”]

Detailed explanation about dynamic module can be found here:

3. APKAnalyser

APK Analyzer in Android Studio can help us understand the amount of memory consumed by different resources in the APK. It provides insights into the composition of the APK and App Bundle.

APK Analyser can be accessed with Build->Analyze APK option in Android Studio

It helps provides the following useful information:

  • View absolute and relative size of the files in the app including DEX and android resources.
  • View the final merged AndroidManifest file.
  • DEX file details including detailed information about referenced and defined methods.
  • View proguard mapping and keep rules.

These insights can certainly help us to analyze our APK and optimize its size. More information can be found here:

4. Removing Unused Resources

Removing unused resources is quite obvious but often ignored. Unused images esp PNG and JPEGs can significantly increase the app size. We also need to be cautious about unused animation files and assets, which have a direct impact on the size of the app.

5. Drawable formats

We must use vector drawables as much as possible rather than using PNG and JPEG images because they consume very high memory in comparison with vector drawables.

We can easily import vector assets using Android Studio. This is by far the most effective yet easiest way to reduce the app size. Vector drawables are easily scalable and their quality does not degrade in the change of size. Thus, we need not have one image for each of the supported resolutions like hdpi, xhdpi etc, which is the case with PNG and JPEG.

In case, we need to support PNG/JPEG for complicated images, we can compress them using image quality tools like TinyPNG.

We can also try to use WebP images, which consume much lesser space compared to PNG/JPEG.

6. Usage of external Libraries

While it’s good to use external libraries to simplify our implementation and to avoid reinventing the wheel, we must be cautious about the size of the dependent library. Some libraries may have many more functionalities than we actually need. These functionalities have their own source code, resources and dependencies. This leads to unnecessary bloating of our source code. It’s better to be aware of the size of the library before using them. Try using lightweight libraries as much as possible.

7. Use Proguard & R8

Proguard helps us in many ways to reduce the size of the APK by removing the unused classes and methods that contribute to the 64K method count limit of an Android application. It also helps to make our app more secure by obfuscating the code, which makes it difficult to reverse engineer.

R8 shrinking reduces the amount of code in our application. It works with Proguard rules and shrinks the code faster while optimizing the output size.

More information about R8 can be found here

8. Resconfig

This can help us remove localized resources, which are not needed.

Resource shrinking removes only resources that are not referenced by the code, which means it will not remove alternative resources(device/location-specific) for different device configurations. resConfigs property can be used to remove alternative resource files that are not needed.

The following snippet shows how to limit your language resources to just English and Italian:

android {

defaultConfig {

resConfigs “en”, “it”

}

}

9. Shrink Resources

Using the shrinkResources attribute in the Gradle will remove all the resources which are not being used anywhere in the project

This can be enabled in App level build.gradle file

buildTypes {

release {

……..

shrinkResources true

……..

}

}

10. Debug Implementation

We need many libraries only in the debug app and not in the release app. e.g Debugging network traffic or database analyser.

This can be specified using debugImplementation dependency in build.gradle.

debugImplementation ‘com.abc.xyz’

These libraries will not be included in the release build and hence help to reduce the size.

While most of the above steps may seem simple, many of them are often ignored.

By following these simple practices, developers can significantly reduce the app size and make their apps more appealing to users. Remember large apps are one of the first ones to be uninstalled by users due to space crunch. While it’s great to have amazing functionalities, developers should not compromise on the app size for this.

--

--