App Size Metrics – Continuous monitoring of App Size, Part 1 | by Akash Khunt | Jun, 2023
App size is one of the very important metric which impacts the conversion rate. The larger the app size the lower the conversion rate.
In fact, Google has found a strong correlation between APK size and install conversion rates, claiming that install conversion rates drop 1% for every 6MB added to APK size. – Taken from GetStream blog.
Whenever a team tries to reduce the apk size the first thing they do is, measure the app size and the contribution by high level categories (i.e. .dex files, resources, assets, JNI libs), which is generally done via Apk Analyzer tool (comes bundled with Android Studio). Then the next step is to look for potential improvements via inspecting the size occupied by each of these categories. This process generally involves converting PNG to WEBP, using proguard rules, using vectors instead of raster assets, etc. In case you’re trying to reduce your apk size and want to know what all can be done then you can read this.
After finishing Size Reduction exercise the thing which often gets missed/ignored is continuous monitoring of the same, which is what we’re going to focus on in this post. Many times teams optimize their apk size but 8–10 months down the line they face the issue of bloated apk size again because they don’t monitors apk size continuously. Continuous monitoring is very helpful because it gives you heads up at the development phase itself and not during later phases like testing (when you might create the release apk for the first time) or release. It also helps you in choosing any 3rd party SDKs when multiple options are available which can suffice your needs. So in this post we’re going to look at how we can implement a solution that can help us with continuous monitoring of apk size.
Building the Script
To help us with continuous monitoring of the apk size we’re going to build a Github Actions workflow which will generate the apk size diff report (using custom python script) whenever a PR is raised and then adds a comment to the PR, containing the size diff report. The final result should look like below:
The workflow is divided into 3 jobs:
- Generate builds for both base branch and a merge branch (i.e. head branch + base branch)
- Generate the size diff report (using custom python script & Apk Analyzer tool)
- Add the size diff report as a PR comment
This step seems very straightforward but there are some caveats as we can’t just run “./gradlew assembleRelease” and then start comparing the apk size. This is because when we build an apk it generally contains the libs/abis for all different supported architectures (i.e. x86_64, armeabi-v7a, arm64-v8a, etc) & resources for all different densities (i.e. mdpi, hdpi, xdpi, etc).
But since the introduction of Android App Bundles, whenever User installs an apk via Play Store, the User gets apk splits very specific to the device in use. This splits include base apk, configurations apks (separate for architecture & screen density), & feature module apks (dynamic feature if used). You can read more about it here.
So the first step is to modify our build script so that it allows us to generate apks for a targeted resConfig (to select single locale for string resources), architecture/abi, & density which will make the comparison easy to understand.
Configuration for resConfig is very straightforward as shown in the below gist.
Here we try to match the resConfig property and set it to “en” (i.e. english). This can be supplied via “./gradlew assembleRelease -PresConfig=en” command where “-P” prefix means it should be treated as a property.
Next we’ll add configuration for abi splits.
Build configuration for abi splits is slightly tricky as it involves more steps. First we’ve to enable the splits, then since all the abis are included automatically first we need to clear it and then include the only ones needed. The required abi can be supplied via “./gradlew assembleRelease -PtargetAbi=arm64-v8a” command.
Build configuration for density split is very similar to the abi one and it can be supplied via “./gradlew assembleRelease -PtargetDensity=xxhdpi” command.
After adding configuration for all 3 we can run “./gradlew assembleRelease -PtargetDensity=xxhdpi -PtargetAbi=arm64-v8a -PresConfig=en” command, which should generate an apk containing arm64-v8a abi, xxhdpi density resources and english string resources.
Since the build configuration is now ready we can start implementing the first step of our workflow i.e. Generate builds for both base and merge branches. One additional thing we’ll do in this job is renaming the generated apks with short SHA of their respective branches’ HEAD commit, this will make the identification of the apks easier as we’ll be uploading the generated artifacts for later use.
To generate the short SHA we’ll use following shell script.
Note: You’ve to put this script in .github/scripts/ directory to make the following job run.
Job 1: Generate builds for both base branch and a merge branch
For keeping this post short I won’t go into details of how exactly the Github Actions work as there are many resources available for the same.
Above script runs whenever a PR is raised against any of the master, main, release/*, feature/* branches (Line 8–10). It also takes care of cancelling the in-progress workflow with the help of concurrency config (Line 4–6).
We’ve also specified outputs (i.e. base_short_sha & head_short_sha) in our build job as we’ll be using them for subsequent jobs.
- Checkout the code using base_ref (PR target branch)
- Setup JDK 17, which might not be required if you’re using AGP versions below 8.0.0
- Setup Android SDK, which also might not be required based on your target SDK and AGP version in use
- Setup cache to make the subsequent jobs run faster via caching all the gradle files, dependencies and android sdk tooling files
- Generate shorter github sha for base branch – This will be used to rename the apk generated from the same branch
- Build release APK for base branch and rename it to match the short SHA generated in previous step i.e. Step 5
- Upload the apk generated in Step 6 – We’ll download this apk in next jobs and also this allows apk download in case someone needs it
- Checkout the code using head_ref
- Here we merge the base_ref branch to head_ref branch to ensure that we’ve all the latest code present in the base branch. This is done to handle the cases where the head branch is not upto date with base branch and some things got added/removed from the base branch.
- Repeat of step 5
- Repeat of step 6
- Repeat of step 7
Once this job completes successfully we’ll get 2 apks generated and uploaded so that we can use them in next job.
That’s all for this post. In the next post we’ll implement next job i.e. Generate the size diff report which will involve the creation of custom python script using Apk Analyzer tool.
- Mobile App Development (625)