Stop generating the BuildConfig on your Android modules

Why generating the BuildConfig class is a bad idea

Maxi Rosson
Nov 21, 2020 · 4 min read

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.

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.

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

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

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

object 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.

You can follow our DipienMedium Publication for more productivity tools & ideas for Android, Kotlin & Gradle developers.

Dipien

Boost your Productivity

Maxi Rosson

Written by

Developer Productivity Engineer | Android | Productivity tools & ideas for Android, Kotlin & Gradle developers on medium.dipien.com

Dipien

Dipien

Productivity tools & ideas for Android, Kotlin & Gradle developers.

Maxi Rosson

Written by

Developer Productivity Engineer | Android | Productivity tools & ideas for Android, Kotlin & Gradle developers on medium.dipien.com

Dipien

Dipien

Productivity tools & ideas for Android, Kotlin & Gradle developers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store