Post

Optimize the build speed for your Android project

We’ve all came to a decision to go and do something else while waiting for the build.gradle to finish, something like: people get married or divorced, learn to fly a plane, build a rocket ship out of LEGO or take one hour poo.

You downloaded Android studio and you just created an empty project and you had it run for the first time right?

Well this should look familiar to you if you profile your build with

1
./gradlew --profile --offline --rerun-tasks assembleDebug

24 seconds, that’s not good.

Alright here we go configuring gradle.

Our first step will be configuring on demand, what does this mean?

Configuration on demand mode attempts to configure only projects that are relevant for requested tasks, i.e. it only executes the build.gradle file of projects that are participating in the build. This way, the configuration time of a large multi-project build can be reduced. In the long term, this mode will become the default mode, possibly the only mode for Gradle build execution.

Inside your gradle.properties

1
org.gradle.configureondemand=true

In case you get some weird error that a task failed mainly using Kotlin DSL scripts or groovy, disable configureOnDemand, you can look at why, at this issue.

It’s good to increase the Java heap memory, of course if your RAM allows it, better not develop apps with <16GB RAM

1
org.gradle.jvmargs=-Xmx1536m -XX:+UseParallelGC

and we’re enabling parallel garbage collection.

You’re building Android projects using Kotlin right, well lemme reveal a dirty secret, if you’ve used KAPT, it’s worker is not enabled, yep, to make it so add

1
kapt.use.worker.api = true

Get ready for more gradle.properties

Building a multi-module project?

1
org.gradle.parallel=true

Get leverage of caching mecnanism? Say no more, in newer versions of Gradle I it’s enabled by default, so there goes another valuable lesson, ALWAYS KEEP your GRADLE up to date with the LATEST VERSION, if you’re unaffected by these caps, just use:

1
org.gradle.caching=true

Using room?

1
room.incremental = true

But wait, that’s not all if you’re using Room, inside your build.gradle find your

1
2
3
4
defaultConfig {

              
}        

and add

1
2
3
4
5
6
7
8
9
10
                javaCompileOptions {
           
                annotationProcessorOptions {
               
                arguments = ["room.incremental":"true"]
           
                }
        }

Get ready for one more gradle.properties addition, ladies and gentleman, the new citizen, configuration cache and it’s brother file watcher

1
2
3
4
org.gradle.unsafe.watch-fs=true

org.gradle.unsafe.configuration-cache=true 

If you decide not to use webP images and stick to PNGs

1
2
3
4
5
6
7
8
9
10
11
                buildTypes {
       
                release {
           
                // Disables PNG crunching for the release build type or maybe
                debug too?
           
                crunchPngs false
       
                }
              }  

Never in your life write dependency using the + format, it adds to the build time if you add just one dependency like this and imagine if you add more, your build won’t even finish by the time you go to sleep, so avoid something like this

1
implementation 'androidx.appcompat:appcompat:1.+'

Many of us use Crashlytics or some form of crash reporting tool, I built my own called Crashy to avoid the slowdowns, leveraging AndroidX Startup and over-configuration of Crashyltics, how can you configure Crashlytics? Well, no worries, there you go.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
buildTypes {

  debug {
     manifestPlaceholders = [crashlytics: "false"]
     crunchPngs false //you can read about that a little bit above

     firebaseCrashlytics {
       mappingFileUploadEnabled false
     }
   }

   release {
      manifestPlaceholders = [crashlytics: "true"]
   }
}

Alright, let’s go step by step:

1
manifestPlaceholders = [crashlytics: "false", analytics: "false"] 

this just disables the crashyltics and analytics from the manifest, but how do you do that?

1
2
3
<meta-data
    android:name="firebase_crashlytics_collection_enabled"
    android:value="${crashlytics}" />
1
2
3
 <meta-data
    android:name="firebase_analytics_collection_deactivated"
    android:value="${analytics}"/>

Wherever your Crashyltics initialization is, just use

1
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(!Buildconfig.DEBUG)

we do the same for the analytics

1
FirebaseAnalytics.getInstance().setAnalyticsCollectionEnabled(!BuildConfig.DEBUG)

mappingFileUploadEnabled

If you don’t need crash reporting for your debug build,you can speed up your build by disabling mapping file uploading.

And now let’s see

We have 4secs build time, including Dagger’s kapt, Nav’s kapt etc..

This post is licensed under CC BY 4.0 by the author.