
Reduce the build time of your Android projects
- Transfer
Good morning! We start Monday with material, the translation of which was prepared specifically for students of the course "Android-developer. Advanced Course . ”

I recently migrated the Android codebase to Kure on AndroidX. It seemed to me that this is a great opportunity to work on the speed of assembly of the project. Gradle has always had a bad reputation due to slowness and resource consumption, but I was very surprised that minor changes to the assembly configuration could increase its speed so significantly.
Look at the assembly scan performance before / after optimization

before optimization

after optimization ️️ Decreased
from 5.5 minutes to 17 seconds ?? Wow!
It's not so difficult to overdo it with optimization to further reduce assembly time. But in order to make the post understandable for beginners, I will deliberately focus on the minor, painless measures that I have taken to get closer to this indicator.
Before you begin optimization, it is important to test our project to find out how long it takes to build it. Gradle has a convenient scan option that you can use to analyze the performance of your task. Launch the terminal in Android Studio and run the following command:
Upon successful completion of the assembly, you will be asked to accept the terms of service to download the scan results. Enter yes to continue. After the publication is complete, you will receive a link to the terminal to check the scan. Open it.
There are quite a few options on the site, but for brevity we will only consider what is most important.
Summary displays summary information about completed tasks and their completion time. But what interests us here is the Performance section . It does a more detailed breakdown of the total build time, as shown below.

In the Performance section there is a Settings and suggestions tab, which provides recommendations for improving assembly speed. Let's look at them.

In this section, we can find some simple fixes to improve speed. So, let's continue and apply these corrections in our project.
The Android team is constantly improving and developing the build system. Thus, in most cases, you can get a significant improvement by simply installing the latest version of the toolkit.
During this refactoring, our project was on version 3.2.1 of the Gradle plugin for Android Studio ( several versions older than the last release ).
You can follow this link to get the latest version of Gradle Plugin. At the time of this writing, the latest was version 3.4.0.
But there is a catch that we must remember:

( Note:When using Gradle version 5.0 or higher, the default size of the Gradle daemon is reduced from 1 GB to 512 MB. This may result in poor assembly performance. To override this default setting, specify the memory size for the Gradle daemon in the gradle.properties file of your project.)
Https://developer.android.com/studio/releases/gradle-plugin
When using Gradle 5.0 and above, we will need to explicitly increase memory size so that the speed of our assembly does not deteriorate. We will return to this in a minute.
Open the top-level build.gradle file , which you will find in the root of your project, and add the following line to the dependency section :
You also need to updatedistribution The URL in the Gradle Wrapper property file located at
( This link will be available on the Android Gradle plugin page . )
You will encounter an error when using Kotlin if the version of the Kotlin Gradle plugin is less than 1.3.0. If so, use the IDE tooltip to update the Gradle plugin for Kotlin to the latest version (at the time of this writing, this is version 1.3.31 ).
Ok, let's run the build again from the terminal to see if we have made any improvements.

So, we were able to cut about 2.5 minutes from the build time, but this is still not good enough. After examining the build logs in the terminal, I came across one line that would interest us:

(> Task: app: compileDevelopDebugJavawithJavac
Gradle can disable incremental compilation, since the following annotation processors are not incremental: butterknife-compiler-10.1.0.jar (com. jakewharton: butterknife-compiler: 10.1.0), dagger-compiler-2.9.jar (com.google.dagger: dagger-compiler: 2.9).
Consider setting the experimental android.enableSeparateAnnotationProcessing-true flag in gradle.properties file to start processing annotations in a separate task and performing incremental compilation.)
Incremental compilation basically prevents wasteful compilation of the entire set of source files and instead compiles only those files that have been modified. From the logs it is clear that we do not use this function. He offers us to use
Fortunately, version 1.3.30 of Kotlin adds support for step-by-step processing of annotations.

https://kotlinlang.org/docs/reference/kapt.html
Starting with version 1.3.30, it
To enable incremental annotation processing, add this line to the file
Note that incremental annotation processing requires that incremental compilation also be enabled.)
So, let's start:
Open
Then change all annotationProcessor configurations in the dependencies section to use kapt. For example: Now open the gradle.properties file located in the root of your project and add the following line: Let's run the build again. Well, it looks like we have made some progress.

We are at the last stage. Remember the trick we encountered while updating the version of the Gradle plugin? It turns out that newer versions of Gradle reduce the size of used memory to 512 MB. This is to ensure that weak machines do not consume too much memory. I have a computer with 16 gigabytes of RAM, so I can afford to feed about 2-3 gigs to the Gradle daemon, but your numbers may vary.
Open the gradle.properties file located in the root of your project and add the following line. Be sure to choose the size to suit your requirements and computer specifications.
While we are doing this, let's also enable parallel assemblies and on-demand tuning in the properties.
Here's what my final version of the file looks like
Having done this, let's see what we now have the assembly speed indicators:


That's it!
This is by no means an extensive coverage of all ways to optimize assembly speed. There are many other things that I have not covered in this post, such as using minSdk 21 when using MultiDex, pre-indexing libraries, disabling PNG compression, etc. are just a few of them.
But most of these configurations require a deeper understanding of the Android build system and experience working with large multi-module projects (where the benefits are most obvious). The steps that I mentioned above are easily implemented by even the junior developers and have significant benefits. I hope this helps you increase build speed!
See you next time, peace be upon you!

I recently migrated the Android codebase to Kure on AndroidX. It seemed to me that this is a great opportunity to work on the speed of assembly of the project. Gradle has always had a bad reputation due to slowness and resource consumption, but I was very surprised that minor changes to the assembly configuration could increase its speed so significantly.
Look at the assembly scan performance before / after optimization

before optimization

after optimization ️️ Decreased
from 5.5 minutes to 17 seconds ?? Wow!
It's not so difficult to overdo it with optimization to further reduce assembly time. But in order to make the post understandable for beginners, I will deliberately focus on the minor, painless measures that I have taken to get closer to this indicator.
Primarily!
Before you begin optimization, it is important to test our project to find out how long it takes to build it. Gradle has a convenient scan option that you can use to analyze the performance of your task. Launch the terminal in Android Studio and run the following command:
./gradlew assembleDebug --scan
Upon successful completion of the assembly, you will be asked to accept the terms of service to download the scan results. Enter yes to continue. After the publication is complete, you will receive a link to the terminal to check the scan. Open it.
There are quite a few options on the site, but for brevity we will only consider what is most important.
Summary displays summary information about completed tasks and their completion time. But what interests us here is the Performance section . It does a more detailed breakdown of the total build time, as shown below.

In the Performance section there is a Settings and suggestions tab, which provides recommendations for improving assembly speed. Let's look at them.

In this section, we can find some simple fixes to improve speed. So, let's continue and apply these corrections in our project.
Step # 1: Upgrade Tools
The Android team is constantly improving and developing the build system. Thus, in most cases, you can get a significant improvement by simply installing the latest version of the toolkit.
During this refactoring, our project was on version 3.2.1 of the Gradle plugin for Android Studio ( several versions older than the last release ).
You can follow this link to get the latest version of Gradle Plugin. At the time of this writing, the latest was version 3.4.0.
But there is a catch that we must remember:

( Note:When using Gradle version 5.0 or higher, the default size of the Gradle daemon is reduced from 1 GB to 512 MB. This may result in poor assembly performance. To override this default setting, specify the memory size for the Gradle daemon in the gradle.properties file of your project.)
Https://developer.android.com/studio/releases/gradle-plugin
When using Gradle 5.0 and above, we will need to explicitly increase memory size so that the speed of our assembly does not deteriorate. We will return to this in a minute.
Open the top-level build.gradle file , which you will find in the root of your project, and add the following line to the dependency section :
classpath 'com.android.tools.build:gradle:3.4.0'
You also need to updatedistribution The URL in the Gradle Wrapper property file located at
gradle/wrapper/gradle-wrapper.properties
. Update the URL to the following. ( This link will be available on the Android Gradle plugin page . )
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
You will encounter an error when using Kotlin if the version of the Kotlin Gradle plugin is less than 1.3.0. If so, use the IDE tooltip to update the Gradle plugin for Kotlin to the latest version (at the time of this writing, this is version 1.3.31 ).
Ok, let's run the build again from the terminal to see if we have made any improvements.

Step # 2: Update Configurations
So, we were able to cut about 2.5 minutes from the build time, but this is still not good enough. After examining the build logs in the terminal, I came across one line that would interest us:

(> Task: app: compileDevelopDebugJavawithJavac
Gradle can disable incremental compilation, since the following annotation processors are not incremental: butterknife-compiler-10.1.0.jar (com. jakewharton: butterknife-compiler: 10.1.0), dagger-compiler-2.9.jar (com.google.dagger: dagger-compiler: 2.9).
Consider setting the experimental android.enableSeparateAnnotationProcessing-true flag in gradle.properties file to start processing annotations in a separate task and performing incremental compilation.)
Incremental compilation basically prevents wasteful compilation of the entire set of source files and instead compiles only those files that have been modified. From the logs it is clear that we do not use this function. He offers us to use
android.enableSeparateAnnotationProcessing=true
, but, in any case, we should not use the “annotationProcessor” configuration since Kotlin is used in our project. Fortunately, version 1.3.30 of Kotlin adds support for step-by-step processing of annotations.

https://kotlinlang.org/docs/reference/kapt.html
(Incremental processing of annotations (from 1.3.30)
Starting with version 1.3.30, it
kapt
supports the incremental processing of annotations as an experimental function. Currently, annotation processing can be performed incrementally only if all of the annotation processors used are incremental. To enable incremental annotation processing, add this line to the file
gradle.properties
: kapt.incremental.apt=true
Note that incremental annotation processing requires that incremental compilation also be enabled.)
So, let's start:
- 1. Change annotationProcessor configuration to kapt
- 2. Enable the experimental incremental annotation processing flag
Open
build.gradle
your module level file and add the following line to the top of the file: apply plugin: 'kotlin-kapt'
Then change all annotationProcessor configurations in the dependencies section to use kapt. For example: Now open the gradle.properties file located in the root of your project and add the following line: Let's run the build again. Well, it looks like we have made some progress.
//До
annotationProcessor 'com.google.dagger:dagger-compiler:2.9'
//После
kapt 'com.google.dagger:dagger-compiler:2.9'
kapt.incremental.apt=true

Step # 3: Gradle Properties
We are at the last stage. Remember the trick we encountered while updating the version of the Gradle plugin? It turns out that newer versions of Gradle reduce the size of used memory to 512 MB. This is to ensure that weak machines do not consume too much memory. I have a computer with 16 gigabytes of RAM, so I can afford to feed about 2-3 gigs to the Gradle daemon, but your numbers may vary.
Open the gradle.properties file located in the root of your project and add the following line. Be sure to choose the size to suit your requirements and computer specifications.
org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
While we are doing this, let's also enable parallel assemblies and on-demand tuning in the properties.
Here's what my final version of the file looks like
gradle.properties
:org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.configureondemand=true
kapt.incremental.apt=true
org.gradle.parallel
- This flag allows Gradle to assemble modules within a project in parallel, rather than sequentially. This is only useful for multi-module projects.org.gradle.configureondemand
- This flag configures only those modules that are necessary for the project, and does not collect them all.
Having done this, let's see what we now have the assembly speed indicators:


That's it!
Concluding observations
This is by no means an extensive coverage of all ways to optimize assembly speed. There are many other things that I have not covered in this post, such as using minSdk 21 when using MultiDex, pre-indexing libraries, disabling PNG compression, etc. are just a few of them.
But most of these configurations require a deeper understanding of the Android build system and experience working with large multi-module projects (where the benefits are most obvious). The steps that I mentioned above are easily implemented by even the junior developers and have significant benefits. I hope this helps you increase build speed!
See you next time, peace be upon you!