February 14, 2022
At Spotify, we strive to make our apps available to as many people as possible. As mobile developers, that means we want everybody to be able to download our app without hiccups or constraints.
One important metric related to this goal is the size of the Spotify app – if it’s too big, users with poor network connectivity or little device storage might not be able to download it. And since shrinking download size has been shown to improve install conversion rate, we aim to keep the app as lean as possible.
But working with app size is not always easy, particularly for large applications with numerous contributors adding cool new features. That’s why we built and open sourced Ruler – a tool to measure and analyze the size of your Android apps, built with automation in mind.
Where we started
We set out to see how we could decrease app size, and started our investigations by using existing tools like Diffuse and Android Studio. Those work great if you want to get a high-level overview of your app, but when we wanted to dig deeper, we quickly arrived at another question – how much are certain modules and dependencies contributing to the overall app size?
The codebase of the main Android Spotify app consists of over 1,000 Gradle modules and hundreds of third-party dependencies. All of these modules and dependencies are merged and packaged into a single app, without a clear way to determine where things came from. This can make it hard to analyze app size and determine where optimization opportunities lie.
Ruler is a Gradle plugin that solves this exact problem. It allows you to analyze your app and gives you detailed insights into the origin and size of certain files, modules, and third-party dependencies.
How does Ruler work?
Android apps are typically packaged and uploaded to the Play Store as App Bundles. The Play Store uses these bundles to generate an optimized Android application package (APK) for every device. Ruler replicates this mechanism (using Google’s Bundletool) to generate an APK for a given device configuration. We do that to accurately measure what ends up on the devices of our users.
Next, we analyze this APK to see which files actually end up in the app and how much space those files take up, leveraging apkanalyzer to ensure the numbers reported by Ruler stay consistent with those analyzed by Android Studio and guaranteeing we measure app size after any. optimizations done by another process (eg R8).
For each file, Ruler captures two measurements:
- Download size: Bytes transferred over the network when a user downloads the app
- Install size: Bytes a file takes up on the device once the app has been installed
Determining the origin of files
After analyzing the APK, we end up with a list of all files and their respective sizes. But how do we determine where they came from? To do that, Ruler scans through all Gradle modules and dependencies included in the build and analyzes which files they contain. The result of this is a second list of all components and their contents. Based on this second list, we can now group all files of the app by their source and therefore determine how much each module and dependency contributes to the overall app size.
Ruler adds a simple analyzeReleaseBundle task to your project, which you can use to execute all this logic. This task will generate two outputs – a JSON report you can use for further processing and an HTML report you can use to analyze and dig into the data yourself.
On Android, all classes are compressed into one or more DEX files. Because we want to be able to see the impact of individual classes, Ruler parses those DEX files and treats every class like a separate file.
When classes are compressed, some information is shared between class entries inside the DEX file. Because of that, it’s not possible to 100% accurately measure how much a single class contributes to the overall app size. Ruler solves this problem by approximating the size of each class by setting the raw class size in proportion to the size of the DEX file.
Knowing which components contribute to the size of an app is great, but knowing who owns these components is even better. Because of this, Ruler supports gathering and analyzing app size ownership data.
If you provide a list of component owners to Ruler, it can analyze the contributions of certain teams to the size of the overall app. This can be helpful to determine who to talk to if questions about certain parts of the app arise.
Ruler at Spotify
We’ve been using Ruler at Spotify for over half a year now and have seen great success. It has allowed us to identify many improvement opportunities and we have been able to reduce our app size by a little over 9% so far.
We export the app size data once a day, using the latest main build. This data is used to track historical trends, both of the app as a whole and of individual modules and third-party dependencies. Additionally, we analyze the app size impact of every pull request, so we can give early feedback to developers and prevent regressions from being merged in the first place.
Start using Ruler today
If you are curious about Ruler, you can try it out today. All you need to do is apply the plugin to your Android project and run a single Gradle task. Check out GitHub for an always up-to-date guide on how you can integrate Ruler.
Contributing to Ruler
Ruler is fully written in Kotlin and leverages exciting technologies like Kotlin Multiplatform. Ruler continues to be actively developed, and we already have many exciting ideas about our new tool. At Spotify, we benefit immensely from open source software, so we decided to open source Ruler and give back to the community.
We’re always looking for input – both raising issues and opening pull requests are very welcome and appreciated. We believe that, together, we can move this project further and help make Android apps accessible to more people.
And if you want to work full time on tools like Ruler, please check out our open job positions – we’re always looking for great minds to join the band.