The mysterious case of the hardcoded properties

When implementing Crashlytics is harder than solving the bugs.


Something we usually hide

Every day, we developers incur in crashes. We may deny it, avoid saying it out loud, but we have them. Mostly, this is thanks to some specific brands of product, but we still need to be aware of them. So we decide to track them down using a tool recently acquired by Twitter.

The project setup

My current task is based on a quite complex architecture made of a top project divided in several flavours that define the final package name and (mostly) UI details, sitting on a common library that will compile an additional video player only for some of the flavours.

Strange requests have been made

One day, one of the clients (aka one of the flavours) asked the team to implement Crashlytics in his release and our PM decided to just include it overall and use different configurations based on clients’ request.

The setup was as easy as the image shows, pretty straight forward, from plugin download to the project up and running.

But I was just so wrong.

Unfortunately, the plugin would not allow us to choose the correct library between those provided by the Fabric suite, forcing us to just integrate it manually, following the instructions provided by the team.

Sheldon was even trying to warn me about it

Implementing it the easy way

Importing the dependencies and the plugins after having read the documentation was fairly easy and we got it up and running pretty quickly. But we noticed something really strange, that suddenly made our duty much harder: Fabric suite needs a fabric.properties file, and it will look out for it right at the root of the project, right next to the build.gradle file and very far away from the flavours folders. There comes the trap. Sheldon was right.

One rough solution

Having the situation clear in mind, we came up with an idea:

What if we ask gradle to write the property file for every client that needs a different pair of key and secret?

Together with my gradle-ninja friend Eugenio, we created a script that was doing it… and it worked out of the box. -ish.

The idea behind it was pretty easy and we could write it down, in pseudo-code, more or less like this:

for each clientFlavour in clientFlavours {
if (exists fabricProperties) {
delete fabricProperties
}

fabricApiSecret = getApiSecretFor clientFlavour
fabricApiKey = getApiKeyFor clientFlavour
    write fabricApiSecret, fabricApiKey to fabricProperties
}

We wrote down the logic and we saw that our task was not able to grab the specific one from Crashlytics. We suddenly realised that, maybe, this crash reporting library was doing the same thing we were trying to do: dynamically creating the task and attaching it to the build sequence, so that we could not really find something to rely on.

Since we could not really create the file before the Crashlytics task, the full build was failing because no properties were found.

But we could still do something to achieve what we wanted and so we did!

This was our face when we had the brightest of the ideas

We studied a little bit more the process and we noticed that, every time, the task

process${variantName}Manifest 

was invoked before Fabric suite could do its magic.

At this point, we decided to hook our task right before the aforementioned one, and make this to depend on ours. Inside our routine, we would then check what kind of flavour we were running into, so we could load the secret data accordingly.

You can find the gist here: https://gist.github.com/tiwiz/b5fac29f4bacc3dfb0c9

TL;DR

We couldn’t integrate Crashlytics using the nice plugin because of our flavour-based key-secret pairs: to solve this specific issure, we created a custom task that generates the requested fabric.properties file for every flavour.

You can find the gist related to this task on GitHub.

Show your support

Clapping shows how much you appreciated Roberto Orgiu’s story.