Today I spent almost two hours on a simple task in a new Android project: make sure that Firebase Crashlytics is enabled in general, but disabled in debug builds.

I ended up simply copy-pasting Crashlytics integration code from one of my older projects. Unfortunately, some of that code looks like black magic and I couldn’t remember why I wrote it in the first place. So, I decided to invest a bit more time to recall why I needed to do it that way and summarize the main points in this article.

Disabling Crashlytics Data Collection in Manifest

Firebase employs a “smart” hack that relies on Android’s ContentProvider to make sure that it initializes automatically after you add the library to your dependencies list. In other words, the sole act of having Firebase SDK as a dependency means that it gets initialized before all other components in your application, including your custom subclass of Application . Therefore, you need to disable data collection before your application actually starts.

To disable Firebase before your applicatoin starts, you need to add the following code to your AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yourapp"> <application ... > ... <meta-data android:name="firebase_crashlytics_collection_enabled" android:value="${crashlyticsCollectionEnabled}"/> </application> </manifest>

The expression ${crashlyticsCollectionEnabled} is called manifest placeholder and its value comes from your main module’s build.gradle file:

android { ... buildTypes { debug { manifestPlaceholders = [crashlyticsCollectionEnabled:"false"] ... } release { manifestPlaceholders = [crashlyticsCollectionEnabled:"true"] ... } } }

Unfortunately, while this setting is absolutely mandatory to disable crashlytics in debug, you still need to explicitly enable Crashlytics in other build types.

Enabling Crashlytics Reporting at Runtime

Even though we enabled Crashlytics data collection in the manifest, my tests show that it’s not enough to actually get the reports. You also need to explicitly initialize Fabric with Crashlytics during runtime of your app in non-debug builds.

The best place to do that is in onCreate() method of your custom Application subclass :

public class MyApplication extends Application { @Override public void onCreate() { ... if (!BuildConfig.DEBUG) { Fabric.with(this, new Crashlytics()); } } }

After this initialization, you should be able to receive reports in your Firebase Console (Crashlytics tab).

Disabling Crashlytics in Debug Builds for Better Build Performance

While the above two steps will ensure that you’ll get crashlytics reports in your Firebase Console, there is still one “minor” issue remaining: build times. To understand the problem, make sure that you’re on “debug” build type and execute “Make Project” command (CTRL+F9 on Windows). Then, immediately after build complection, execute the same command again.

Theoretically, since nothing changed, Gradle should avoid executing most (or even all) tasks. However, with the current configuration of Crashlytics, you’ll most probably see something like this:

That’s not good because you might be building debug APKs tens or even hundreds times a day, so this overhead will quickly add up. In addition, it looks like the overhead itself depends on the size of the app, so you can expect it to increase as your application grows.

To fix this problem, add one additional directive to your main module’s build.gradle file:

android { ... buildTypes { debug { manifestPlaceholders = [crashlyticsCollectionEnabled:"false"] ext.enableCrashlytics=false ... } release { manifestPlaceholders = [crashlyticsCollectionEnabled:"true"] ... } } }

After you add this flag, Gradle will be able to optimize you debug builds much better. So, the same flow as above will yield results like this:

Conclusion

In this post I summarized the black magic that you need in your codebase to disable Firebase Crashlytics in debug builds.

I should probably also say that this setup is absolutely unintuitive and it’s crazy that you need to write obscure code in three different places for such a trivial task. However, I performed many experiments in two different projects while writing this article, and it looks like you indeed need all this code.

There seems to be additional way to disable Crashlytics in debug builds by using releaseImplementation instead of implementation directive for Crashlytics SDK in your main module’s build.gradle file. However, I never used this approach in production so I can’t vouch for it to work.

It’s interesting to note that the aforementioned blog post from Firebase team states:

I think the convenience for developers using Firebase more than makes up for this strangeness of this use of a ContentProvider. Firebase is all about being easy to use, and there’s nothing easier than no code at all!

Well, sadly, “convenience for developers” and “no code at all” didn’t work quite as they expected for real Android projects.

As usual, leave your comments and questions below, and please let me know if I missed anything in my analysis.