Tracking Android app metrics

| 2 minute read | android apk size

When I joined Monzo I was keen to keep a track of metrics that would help us keep a handle on the app’s size and method count. I set up a shell script on our CI to upload the numbers to StatHat each time we merged a change to our develop branch. This was great in theory, but not visible enough to be actually useful - in fact, one of the stats stopped uploading properly some months ago and we didn’t even notice.

We recently started using Danger and I thought it would be a great opportunity to surface these numbers, so we could actually see the impact of each change being merged into the app.

Step 1 - Upload stats when merging into develop

The StatHat docs are really helpful here, there are many ways to upload a stat so pick your favourite. I went with Ruby.

Uploading the apk size is pretty simple once you’ve found the right path to it.

#!/usr/bin/env ruby
require 'rubygems'
require 'stathat'
def apk_size()
File.size("app/build/outputs/apk/flavour/debug/app-flavour-debug.apk")
end
StatHat::SyncAPI.ez_post_value("apksize", "YOUR_EZKEY", apk_size())

The method count is tricker - we’ve use this plugin on our build which outputs a CSV with the method counts and it’s been working perfectly. I just needed to whip up some command line magic to extract the right number ✨

def method_count()
# Ignore the first line of the CSV and take the 1st column
`tail -1 app/build/outputs/dexcount/flavourDebug.csv | cut -d ',' -f1`.to_i
end
view raw method_count.rb hosted with ❤ by GitHub

How/where you run this script will depend on your setup - we use CircleCI.

- run:
name: Upload APK size/method count statistics to StatHat (only runs on develop)
command: |
if [ ${CIRCLE_BRANCH} = 'develop' ]; then bundle exec upload_stats.rb; fi
view raw circle.yml hosted with ❤ by GitHub

Step 2 - Retrieve stats from develop

Next up, we need to be able to retrieve the stats we’ve uploaded to compare the latest develop against what we have locally. This was trickier, as you can only retrieve raw data points from StatHat, so we need to filter down all the points and get the most recently uploaded stat.

# Retrieve most recently uploaded size of apk on develop by their id
# All stats: https://www.stathat.com/x/ACCESSTOKEN/statlist
def apk_size_develop()
get_stat("https://www.stathat.com/x/ACCESSTOKEN/data/ID")
end
# Helper, get most recent stat from StatHat by url
def get_stat(url)
uri = URI.parse(url)
response = Net::HTTP.get_response(uri)
# Api returns an array of points with time and value, filter out 0 values and take the last
JSON.parse(response.body)[0]['points'].select { |time| time['value'] != 0}.map { |time| time['value'] }.last() || 0
end

Step 3 - Comment on pull request with changes

Finally, we need to put it all together. We retrieve the apk size from the local branch and compare it against the what it is on develop. Danger runs on CI for all branches (except develop, master and release-*) and will warn us by commenting on the pull request if the app size has changed by more than half a MB.

require 'humanize-bytes'
apk_size = apk_size() # Apk size from local branch
apk_size_develop = apk_size_develop() # Apk size from stats uploaded to StatHat
difference = Humanize::Byte.new(apk_size - apk_size_develop)
warn "APK size has changed! Now: %.2fMb; on develop: %.2fMb. Difference: %0.2fKb" % [Humanize::Byte.new(apk_size).to_m.value, Humanize::Byte.new(apk_size_develop).to_m.value, difference.to_k.value] if difference.to_k.value.abs > 512
view raw Dangerfile hosted with ❤ by GitHub

Originally I had it showing a warning if the apk size didn’t exactly match, but that meant it posted on every PR. We felt that if it posts on every change, it will likely start to get ignored - so instead set an allowable range.

That’s it! It’s been running for the past week and is working really well so far.


If you enjoyed reading this post, you can find me on twitter @emmaguy