Remove unused Android resources to reduce APK size

I’ve been programming Android applications for 2.5 years. I mainly work on the KeepSafe Hide pictures app but I also built our Hide SMS app and some other small private projects.

Over time, one problem I keep running into over and over again is dealing with resource bloat — which happens when you keep adding new resources but there’s no good way to remove the ones that are no longer in use. In a typical web project, resource bloat doesn’t really affect performance because the browser will only load what’s needed. On mobile, however, it’s a real problem because space is much more of a commodity, and all of your unused resources will end up getting shipped to the user.

To fix this, I wrote a small tool called android-resource-remover that pinpoints unused resources and removes them from your codebase.

The problem

In Android, resources are everything. Your layout XML files define your views, images, strings, colors, dimensions, animations, and so on. Different screen densities across different devices make you store every image in 4–5 different resolutions with the same name in different folders. In cases with graphical buttons, you need to provide a different image for different button states and then wire it all up in an additional XML in your drawable folder. This makes it easy to have one button in 11 different files. The same goes for strings; e.g. our app is translated into 10 different languages. Adding a new string to the app will introduce a new <string> tag in 10 different XML files.

If I want to stop using a button, I have to find out what image resources my drawable XML is using and then delete everything. In the case of the string that I just defined, I have to delete the string in those 10 different files and remove them inline.

Because there’s so much overhead and manual work, I pretty much never did resource cleanup.

Solution and Usage

Today, the Android Developer Tools come with a tool called Lint that gives you great output on what is unused in your codebase. However, you still have to remove everything yourself. For this reason we wrote a small tool called android-resource-remover that will remove all of your unused resources based on Lint’s output.

pip install android-resource-remover

Usage is pretty easy too. You just run

android-resource-remover

in your Android project directory. android-resource-remover expects that you have lint in your classpath. In case you don’t, you can specify the location of your lint tool with \ — lint

You can find more information about how to use it and the source under https://github.com/KeepSafe/android-resource-remover. In case you built your Android project with gradle, tale a look at the tools README for instructions.

One thing to note is that you might have to run android-resource-remover twice because of dependencies. In other words, new unused resources will likely emerge after you run it for the first time. For instance, an unused layout in your code will be removed on the first run. Then, when you run it again, it will point out all the strings and graphics that have been used by this layout, as there is no reference to them anymore.

One thing to note is that you might have to run android-resource-remover twice because of dependencies. In other words, new unused resources will likely emerge after you run it for the first time. For instance, an unused layout in your code will be removed on the first run. Then, when you run it again, it will point out all the strings and graphics that have been used by this layout, as there is no reference to them anymore.

What is the difference in APK size after running android-resource-remove on our hide pictures app? I branched off from our develop branch to build a different APK after removing all unused resources to compare file size. The result is quite fascinating. Even with our rather large app (due to native code and other libs), I can reduce the APK size by 10% by shaving off ~1MB. Here is a ls -la output of that dir.

ls -la
-rw-r--r-- 1 philipp staff 10M Apr 30 09:22
App_without_unused_resources.apk
-rw-r--r-- 1 philipp staff 11M Apr 30 09:07
App_including_unused_resources.apk

How does it work?

android-resource-remover is based off the result XML from the Android Lint tool. There are other tools out there that tell you about unused resources, but we feel strongly about using the output of the most supported tool over time. In this case, Lint from the Android project itself seemed like a solid approach; it allowed us to focus on removing the actual resources from disk and from within the other XML resource files.

Lint tool gives you a lot of things you can use to improve in your app. For this project, we’re only looking at improvements that are tagged with UnusedResources. So we’re parsing the entire output XML for

root.findall('.//issue[@id="UnusedResources"]')

The slightly tricky part is that Lint output is not currently made for tools like this, so there is no clear indication if a resource is an entire file or just a single element in a resource.xml file (e.g. string.xml). Our current approach is to look at the location value of the unused resource from Lint’s output. If it contains line or column, we expect the resource to be within a file and not the entire file.

From here on it’s pretty easy: resources that are an entire file just get deleted. For resources that we identified as an element within a XML file, we first parse the resource XML and then remove that element. All this happens in the android_clean_app.py either in remove_resource_file() or in remove_resource_value().

While writing this, I’m contemplating whether we should just commit a patch to the Android Lint tool that gives us a more clear output about a resource being a value within a XML file or an entire file.

I hope this will help as many Android developers over time as possible. I’m very happy to hear your comments, suggestions, experiences and how you think we can improve android-resource-remover. Feel free to submit bugs or open pull requests for improvements.


Originally published at keepsafe.github.io on May 15, 2014.