A journey to a smaller APK
A journey to a smaller APK
Once upon a time I interviewed someone for a software engineer position. As a part of the interview process we let the candidate ask us questions. This candidate asked us, “Why is the installation file (.apk) for your app so big?”. At that moment the installation file was almost 63 MB. Receiving such a question we realized the candidate had a point. The APK was actually very large and we had to do something about it. So we started thinking how we could improve the situation. We want to share the results of that with you.
Our first step was to inspect the .apk file and understand what it contained. Thankfully, Android Studio provides such a tool. It is accessible through the menu ‘Build -> Analyze APK…’.
You can see the result of the analysis below.
The tool showed us that 90% of the APK file was resources. It was clear our main focus should be on optimizing resource files.
Remove unused resources
There’s a quick way to optimize resources: If you don’t use any resources, simply delete them. It can happen that some of the resources may be forgotten. Using the Lint tool will help you to identify unused resources and you can delete them.
Optimize video files
Our app has a couple of videos in order to make it more attractive and catch the user’s attention. Having a few of them can increase the final APK size significantly. We decided to give all video files to the content team for optimization. Since they are experts in video, we knew they would take care of it in the best way.
We did exactly that. We received optimized and lightweight video files. But to understand what changed, we inspected the files’ details before and after optimization and found the following differences:
|Overall bit rate||3 235 kb/s||735 kb/s|
|Stream size||4.77 MiB (94%)||963 KiB (81%)|
|File size||5.3 MB||1.2 MB|
The result of optimization was reducing apk file by 10 MB.
Optimize audio files
The situation with audio files was pretty similar. Our app uses audio files mostly to notify users about their training progress: like telling them what minute of the training they are performing or if the training is over. We passed them to the content team, which shrunk the files before giving them back. We did the same analysis on the audio files that we had done on the video files to learn what had changed. Below are the results:
|Bit rate||256 kb/s||32.0 kb/s|
|Channel(s)||2 channels||1 channel|
|Sampling rate||44.1 kHz||16.0 kHz|
|File size||56.4 KB||13.7 KB|
The file sizes were quite large – too large for their function. Since audio files are mostly used for quick training updates, we don’t need, for example, to have stereo audio files with the highest bitrate. The content team did a great job of reducing file size according to the needs of the app.
The result of this optimization was reducing the apk file by 4 MB.
Quality images are the main part of the content in the app. And it’s very important not to sacrifice image quality to reach the goal of a smaller APK. Still, optimization had a huge impact on the APK file. It was reduced by more than 25 MB.
One of the decision we made based on data from Google was to support only 3 densities: hdpi, xhdpi and xxhdpi. Those image densities should cover already more than 90% of devices.
For all icons we are using now vector drawables. At the end it’s only one file for icons for all resolutions instead of the set of files for each density.
We have converted all our images to .jpg format. Jpg images are lighter and use less memory than .png. In case we needed to have transparency (alpha channel) we used files in the .webp format. Webp is a format for drawables recommended by Google to use instead of .png. We converted them with the help of our designers. But it’s possible to do it from Android Studio from the context menu of the picture.
Based on our own discovery we found that pictures for each density usually have approximately the same size on the disk. The size of each file in hdpi folder is roughly 50 KB, in xhdpi is ~100 KB and in xxhdpi is no bigger than 200 KB. Files exceeding those limits were sent to the design team, so they could shrink and optimize them without visible quality loss on mobile.
Freeze the size
Working in teams requires collaboration and communication with each other. We faced the issue that while one team was optimizing resources and did a clean up, another team accidentally brought big unprocessed drawables into the app. It looked like a step back. As engineers we thought that this was a good case for an automated solution to inspect APK size on each change. We developed a script which checks the size of the APK file on each pull request. If the APK exceeds the threshold, the job on CI fails and the pull request is blocked. This can be like a warning that something has gone wrong and more attention is required.
The script is simple and you can use it for your purpose as well:
PATH_TO_APK=$1 APK_THRESHOLD=$2 NEW_APK_SIZE=`expr $(stat -c%s PATH_TO_APK) / 1024` echo "APK size now is "$NEW_APK_SIZE" KB if [[ $NEW_APK_SIZE -lt $APK_THRESHOLD ]]; then echo "APK file is less than "$APK_THRESHOLD" KB. OK" else echo "APK file is above the threshold of "$APK_THRESHOLD" KB. Failed" exit 1 fi
Summarizing the work we did, our app became leaner from 63 MB down to 24 MB. Isn’t that amazing?