Stop generating the BuildConfig on your Android modules

This article will explain why I believe that generating the BuildConfig class for Android library modules is a bad idea. It’s important to highlight that I am not talking about the app module BuildConfig, I am talking about all the other BuildConfig files generated by each android module.

First of all, I would like to clarify some terms, so you better understand this article:

  • when I say debug code, I am talking about the code available on the local builds used by developers when they pick the debug variant. It is typically located at src/main & src/debug source sets.
  • when I sayrelease code, I am talking about the code distributed on your release APK/AAB. It means the release variant. It is typically located at src/main & src/release source sets.

The Reasons

These are the main reasons to disable BuildConfig.java generation:

  • Generating the BuildConfig file for each module has a build speed penalty
  • BuildConfig is generated as a Java file. But having a module with mixed Java & Kotlin code impacts on build speed. You can read more about this, in this great article.
  • Having a BuildConfig per module could be confusing for developers when they need to pick which one to use
  • BuildConfig presence stimulates developers to use BuildConfig.DEBUG and have debug code mixed with release code

The last reason is very important, so I would like to clarify it.

The more common usage of theBuildConfig is to do something like this:

if (BuildConfig.DEBUG) {
// do something for debug only
}

But that kind of logic has some issues:

  1. It adds complexity to your code because you have mixed release & debug logic in the same place.
  2. It stimulates developers to add more debug code in the src/main source set. This is not good, the code you use in your local environment (debug variant) should be as close as possible to your production code (release variant).
  3. This could potentially increase the size of your production code. I say “potentially” because after some compiler optimizations + Proguard/R8 most of the debug code will be probably removed from the released AAB.
  4. If you decide to migrate your module code to an external android library, you are not going to be able to continue using BuildConfig.DEBUG, because you probably are going to have just one variant of your library published on a maven repository.

The proposal

As a first step, you could migrate all your debug code from the src/main to the src/debug source set.

Remember that all the code you put on the src/debug is not going to be included on the release APK/AAB.

You can use some tricks like class overriding between different variants. For example:

On src/main/com/sample/App.kt

class App {
fun doSomething() {
Executor.execute()
}
}

On src/debug/com/sample/Executor.kt

class Excecutor {
fun execute() {
// This code will be executed only on the debug APK/AAB
}
}

On src/release/com/sample/Executor.kt

class Executor {
fun execute() {
// This code will be executed only on the release APK/AAB
}
}

As you can see, with that approach your debug and release code is properly separated, giving clarity to your code. According to the picked variant, the proper Executor class will be used.

You can use the same approach if, for example, you need to use different backend URLs for debug & release and you are currently configuring them on a module’s BuildConfig. For example:

On src/debug/com/sample/Server.kt

object Server {
const val SERVER_URL = "http://dev.sample.com"
}

On src/release/com/sample/Server.kt

object Server {
const val SERVER_URL = "http://production.sample.com"
}

Once you finished with the migration of all the debug code, you can configure your gradle.properties to stop generating the BuildConfig file by default on all your android modules:

android.defaults.buildfeatures.buildconfig = false

Take into account that the BuildConfig on your app module is useful. It has the app version code, version name, application id and any custom flag you decided to add. So, I recommend to keep it (but remember to avoid using BuildConfig.DEBUG). So, to override the default behavior defined on gradle.properties, just add the following configuration to yourapp/build.gradle

android {
buildFeatures {
buildConfig = true
}
}

After that, you will only have one generatedBuildConfig for the whole app and your code will be properly distributed between debug & release source sets.



This article contains Affiliate Links. If you purchase anything after clicking an affiliate link, I may receive some compensation.

If you want to learn Android, here you have some recommended books

Comments

Popular Posts

Circle CI + Android configuration tips

Versioning Android apps

Say bye-bye to Android Jetifier