Remote Config in Android — one release to rule them all!

How I developed a remotely configured Android app without losing my sanity

First, a tale

So you’re an Android developer, you’ve been working really hard on the latest version of your app, added sexy new features, fixed all critical bugs, polished the UI, released it to the store, you monitor the analytics reporting andddd

it sucks.

So now you’re probably thinking to yourself:

Let’s change this and that and release another version, this time I know they’ll love it!

Whoops, the new version performs even worse than the last.

OK, back to drawing board! but meanwhile you have this feature causing havoc in production so you decide to release another version without that god-forsaken feature so you have time to reevaluate your life choices.

Seems tedious, right?

But as developers, most of us have been there, features that seem great in our minds roll out and get a cold shoulder from our users.

Remote config to the rescue

Remote config basically means you’re allowing a portion of your app to be configured from the server side, saving you the hassle of releasing a patch version every time you wish to make a minor change and allowing you to A/B test new features.

Suppose you’ve decided to add a shiny “Rate Us” button on your app’s main screen which sends your users to the play store to rate your app but you’re afraid this button might annoy users.

Moreover, you’re having a tough time deciding about the position and size of this new button.

At this point since you’re familiar with the concept of remote config you decide to control this button remotely so you don’t end up releasing more versions.

Firebase has got your back(end)

The good guys at Firebase implemented a remote config mechanism for us,

so let’s play with it a little.

Add dependency:

Init SDK and load the remote config values:

Now that we’re set up, let’s control whether our new rate button is visible to users:

But wait, what if no one configures any value in the remote config for this key? We need to define a default local value:

Looks simple enough.

But what if we want to limit the number of times the user can see the button?

Let’s add another config to control this

(for brevity I will skip the actual implementation of making the button disappear after X times):

But then again, reading this value as-is isn’t exactly safe.

What if someone configured a negative value?

What if in no scenario we want to allow the user to see the button more than 3 times?

We need to add extra processing code:

DEFAULT_MAX_TIME_TO_SHOW is the same value we provide to FirebaseRemoteConfig in the init phase using the default values map.

Now suppose we want to control the position of the button, choosing between top, center or bottom.

We will have to define a Long value for each value since we’re limited to primitive types in remote config.

We’ll also have to deal with invalid values:

We can control all sorts of properties of our button remotely but we will have to deal with validation and processing of the remote values over and over again.

What if we wanted to normalize the way config values are validated and processed?

What if we want to locally override a remotely configured value?

What if we want to mock configured values locally for testing purposes?

What if we want to migrate from Firebase to our own remote config server side implementation?

As you can see, things can get quite complicated once we start using remote configs excessively.

Introducing AirCon — control over the air

Fortunately, it only takes one frustrated developer (myself in this case) to create a library that can make other developers’ lives easier.

AirCon is an Android library based on annotation processing designed to simplify handling of remote configs by generating boilerplate code for you and providing easier access to remotely configured values.

Let’s revisit the rate button example.

Using AirCon we can define an interface containing all the remote configs related to our rate button, making it more readable and easier to alter in the future:

During compile time, the AirCon processor will find all your remote config interfaces annotated by @FeatureRemoteConfig and generate a provider class for each one:

Simple, clean and maintainable (3 words to make any developer happy).

Controlling the source of your remote config

The source of the remote config is determined by the @Source annotation on the remote config interface.

In the above example we’ve used AirCon in conjunction with Firebase but any custom config source can be used so switching from Firebase to your own backend solution will take no more than a couple of minutes.

You can implement a custom source by creating a class implementing the proper AirCon config source interface.

Non-primitive configs

AirCon supports non-primitive configs for common use cases like reading a remotely configured Json string and converting it to a POJO:

Mocking config values

Testing how your app behaves with different configured values is made easy with AirCon using config mocks:

AirCon is also equipped with custom lint checks so lint will fail your build if you try to build a release version with mocks values.

Remote branding

Controlling colors and text remotely is a common use case for remotely configured apps.

AirCon allows you to inject remotely configured values directly to you android XML layout:

All you need to do is define attributes corresponding to the keys of your remote configs (in the above example aTitle and aTitleTextColor ) and let AirCon do its magic.

Summary

I personally believe all apps should use remote config to some extent.

It is a powerful tool which can save you a lot of time and energy on releasing patch versions and allow you to better control your users experience.

Unfortunately, powerful tools tend to be complicated to use by nature; therefore I hope AirCon will make your life a bit easier and help you enter the fun world of remotely controlled apps.

Read more and start using AirCon at:

https://github.com/ironSource/aircon