Stephan's Stuff

Adventures in Android Development

Reduce APK Size

My app size is too big and I want to find out why.


I recently released my app Stopmotion to the Google Playstore. The functionality is, as the name suggests, you can make stop motion movies, or more precise, gifs with it. You take some pictures in a specific interval and the app creates a looping gif out of them. You can then share the gif with your friends, view it and delete it if you want so. Of course I showed it around to get some feedback and a coworker of mine asked me why the APK is so big in download size. Looking at the size of the file he was right, for the functionality what the app has, I have to admit it is quite big. Speaking in numbers: the version in the Playstore has a download size of 7.43 MB. That’s not huge, but still pretty big for such an app. In this blogpost I want to show what I did to identify why the APK is so big and what to do to reduce its size.

Identifying the reasons

With Android Studio 2.2 there comes a new tool for analyzing APKs, which can be found at the menu item: Build -> Analyze APK…. This tool visualizes the content of your APK and gives you an overview what specifically takes how much space. I used to analyze my release candidate for Stopmotion. As you can see in the screenshot it shows you the filename, the raw file size, the downloaded size and the percentage of the size of every item inside an APK. In my case the biggest part in my app is the lib folder. The reason for this is that I use Realm as a database and Realm is written in C++ and uses dynamic libraries, which are stored in the lib folder.
But why is it so big? To answer this question you have to understand that Android supports different types of processor architectures1. And if you provide a library, as Realm does, you basically want to support all of them. This means that for each and every architecture you have to create an own shared object file(.so) file and store it in your APK(this is done by the Android NDK). Realm supports 6 architectures and everyone of them has between 1 and 2.5 megabytes in size. And they are all in my APK and make it big. The good thing is that Android is pretty smart sometimes, during the installation process on your phone it figures out which architecture you have and then delete the not needed .so files, so the not needed files will not stay on the phone.
But still the user has to download all of them onto his phone, even if only one is needed.

Building for specific architectures

Since we only need one ABI per phone and those are one of the main reasons why my APK is so big, they have to be removed. Good thing is that it is possible to release different APKs to the Google Playstore and it is also possible to tell gradle that only specific architectures should be supported for the APK. This can be easy done by adding the following to you build.gradle:

1
2
3
4
5
6
7
8
splits {
    abi {
        enable true
        reset()
        include 'x86', 'armeabi-v7a', 'mips'
        universalApk false
    }
}

This will create an APK for every architecture, which then can be pushed to the Google Playstore. The Analyze APK… tool let you also compare APKs to each other. If we now compare the APK with one architecture to the original one, there is a diff from around 10 megabytes in the downloaded size, as you can see in the picture. This is a big step into the right direction, but still there can be more optimized to shrink the filesize.


Identifying the reasons(part two)

The next big file is the classes.dex file which is 2.4 megabytes in total and contains all the code the APK has. The new analyze tool can also open a dex file and give an overview what’s going on there. You probably heard of the 64k reference limit2 and it’s bad practice to exceed it. Checking my count I can see a total of 48069 references which is pretty close to 64k, for such a small app. Digging deeper I found out that only 898 are from me and the rest is from the system and libraries I use. In order to minimize the method count as well as the APK size the tool Proguard3 can be used.

ProGuard is a Java class file shrinker, optimizer, obfuscator, and preverifier.

In order to use Proguard it has to be enabled in the build.gradle file and a the rules(for keeping specific code) has to be specified. You can turn Proguard on by setting minifyEnabled to true in your release build type and then you only have to specify the above mentioned rules in the proguard-rules.pro file. Additionally to Proguard, which shrinks your code, you can also let your resources shrink. This can be done by adding shrinkResources true to your release build type and results in removing unused resources during the process of creating your APK. But you have to keep in mind that this is consecutive to minifyEnabled and therefore just works when Proguard is enabled.
After enabling Proguard my reference count shrunk from 48069 to 23180, which is a decrease from around 51%! That’s pretty good and now I’m far from the 64k limit away. And if that would not be enough, the size of the dex class file shrinked by 4 megabytes! The removing of the unused resources brought about 290 kilobyte, which is mostly because there aren’t many resources at all.

Conclusion

After splitting the APK into architecture specific files and using Proguard to decrease the reference count as well as the classes.dex file size my app has now a downloaded file size from 2.4 megabytes.
Compared to the 7.4 megabytes before this is 67.5% my downloaded APK is smaller now.
I think that is a huge improvement and I’m very happy about it. Even if you don’t have any native code which bloats you APK you can still decrease the size of your APP by just enabling Proguard. Having a final look at the APKs before and after shrinking you will see it is worth it.



TL;DR Use the new Analyze APK… tool to identify the thickener of your APK. Split APKs for different architectures. Enable Proguard and remember: #perfmatters