Oh my!!! I have two hours left to deliver this app, but this Gradle keeps building my project. It’s taking forever to complete, what am I going to do?
This was an experience I had with gradle when I started android development. It can suck the life out of you if you don’t understand the nitty gritty of this build system.
Have you ever wondered why it takes gradle lots of time to build an android project successfully?
Long build times slow down your development process, so this article offers some techniques to help you resolve build speed bottlenecks.
Let’s start from the bottom….
What is Gradle?
Gradle is an easily customizable build system that supports building by a convention model. Gradle is written in Java, but the build language is Groovy DSL (domain spec language). Gradle not only supports multi-project builds, but it also supports dependencies like Ivy and Maven. Gradle also can support building non-Java projects.
The entire process of improving your build speed is as follows:
- Optimize your build configuration by taking a few steps that immediately benefit most Android Studio projects.
- Profile your build to identify and diagnose some of the trickier bottlenecks that may be specific to your project or workstation.
When developing your mobile app, you should deploy to a device running Android 7.0 (API level 24) or higher whenever possible. Newer versions of the Android platform implement better mechanics for pushing updates to your app, such as the Android Runtime (ART) and native support for multiple DEX files.
A. Optimize your build configuration
- Keep your tools up to date: The Android tools receive build optimizations and new features with almost every update, and some tips on this article assume you’re using the latest version. To take advantage of the latest optimizations, keep your Android Studio and SDK tools and the Android plugin for Gradle.
- Create a build variant for development: Many of the configurations you need when preparing your app for release are not required while developing your app. Enabling unnecessary build processes slows down your incremental and clean builds, so configure a build variant that keeps only the build configurations you need while developing your app. The following sample creates a “dev” flavor and a “prod” flavor (for your release version configurations):
android {
...
defaultConfig {...}
buildTypes {...}
productFlavors {
// When building a variant that uses this flavor, the following configurations
// override those in the defaultConfig block.
dev {
// To avoid using legacy multidex when building from the command line,
// set minSdkVersion to 21 or higher. When using Android Studio 2.3 or higher,
// the build automatically avoids legacy multidex when deploying to a device running
// API level 21 or higher—regardless of what you set as your minSdkVersion.
minSdkVersion 21
versionNameSuffix "-dev"
applicationIdSuffix '.dev'
}
prod {
// If you've configured the defaultConfig block for the release version of
// your app, you can leave this block empty and Gradle uses configurations in
// the defaultConfig block instead. You still need to create this flavor.
// Otherwise, all variants use the "dev" flavor configurations.
}
}
}
If your build configuration already uses product flavors to create different versions of your app, you can combine the “dev” and “prod” configurations with those flavors by using flavor dimensions. For example, if you already configure a “demo” and “full” flavor, you can use the following sample configuration to create combined flavors, such as “devDemo” and “prodFull”:
android {
...
defaultConfig {...}
buildTypes {...}
// Specifies the flavor dimensions you want to use. The order in which you
// list each dimension determines its priority, from highest to lowest,
// when Gradle merges variant sources and configurations. You must assign
// each product flavor you configure to one of the flavor dimensions.
flavorDimensions "stage", "mode"
productFlavors {
dev {
dimension "stage"
minSdkVersion 21
versionNameSuffix "-dev"
applicationIdSuffix '.dev'
...
}
prod {
dimension "stage"
...
}
demo {
dimension "mode"
...
}
full {
dimension "mode"
...
}
}
}
- Avoid compiling unnecessary resources: Avoid compiling and packaging resources that you aren’t testing (such as additional language localizations and screen-density resources). You can do that by only specifying one language resource and screen desnity for your “dev” flavor, as shown in the following sample:
android {
...
productFlavors {
dev {
...
// The following configuration limits the "dev" flavor to using
// English stringresources and xxhdpi screen-density resources.
resConfigs "en", "xxhdpi"
}
...
}
}
- Disable Crashlytics for your debug builds: If you don’t need to run a Crashlytics report, speed up your debug builds by disabling the plugin as follows:
android {
...
buildTypes {
debug {
ext.enableCrashlytics = false
}
}
You also need to disable the Crashlytics kit at runtime for debug builds by changing the way you initialize support for Fabric in your app, as shown below:
// Initializes Fabric for builds that don't use the debug build type.
Crashlytics crashlyticsKit = new Crashlytics.Builder()
.core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
.build();
Fabric.with(this, crashlyticsKit);
If you want to use Crashlytics with your debug builds, you can still speed up incremental builds by preventing Crashlytics from updating app resources with its own unique build ID during every build. To prevent Crashlytics from constantly updating its build ID, add the following to your build.gradle
file:
android {
...
buildTypes {
debug {
ext.alwaysUpdateBuildId = false
}
}
Wonderful!!!
Lets take a pause here…
I have lots of gradle build best practices I would like to share with you. However, I am going to share the second half in my next article.
Remember one thing….
A world class app is defined by its quality and efficiency. This is achievable when best practice is your priority…
No Comment! Be the first one.