Beginner's Guide to Understand Build Gradle Files in Android Studio

An overview of build Gradle files (settings.gradle/.kts, build.gradle/.kts, and gradle.properties) used in Android Studio for beginners

ยท

9 min read

Beginner's Guide to Understand Build Gradle Files in Android Studio

Build Gradle is a build tool used in Android Studio to build your Android app. It can be written either in Groovy script, or Kotlin script (KTS). KTS is newer than Groovy and eventually, it will replace Groovy.

High-level functions of Build Gradle

  1. Reads app's build configurations/scripts (settings.gradle / settings.gradle.kts and build.gradle / build.gradle.kts)

  2. Downloads and caches app's dependencies from repositories that you specify in settings.gradle / settings.gradle.kts

  3. Compiles the app's source code (either Java or Kotlin) into Java Bytecode, followed by Dalvik Bytecode.

  4. Packs the Dalvik Bytecode and resources either into the APK (Android Package) or Android App Bundle

To do all these functions above, the following Gradle build configuration/script files are needed

  • settings.gradle / setings.gradle.kts (root directory)

  • build.gradle / build.gradle.kts (root directory)

  • gradle. properties (root directory)

  • build.gradle / build.gradle.kts (module directory - e.g. app directory)

All code examples below are based on Kotlin script (KTS).

settings.gradle/settings.gradle.kts

The main purpose of settings.gradle/settings.gradle.kts is to provide the repositories which specify where to download plugins and dependencies needed for your app.

pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()

        maven ("https://jitpack.io")
    }
}
rootProject.name = "New Empty Compose App"
include ("app")

pluginManagement

It configures repositories where plugins can be resolved/downloaded from gradlePluginPortal(), google() and mavenCentral(). All these are just function calls to set up the repository location.

What are plugins? plugins provide tasks/functions to build.gradle /build.gradle.kts to build your Android app

  • gradlePluginPortal() set up the repository hosted at plugins.gradle.org. Kotlin Android plugin(org.jetbrains.kotlin.android) is an example that is provided in this repository. Ca

  • google() set up the repository hosted at maven.google.com. Android application project plugin (com.andoird.application) and Android library project plugin (com.android.library) are 2 common plugins that are provided in this repository.

  • mavenCentral() set up the repository hosted at repo.maven.apache.org which is a popular repository. Most apps probably do not need this, but maybe it is a good practice to leave it here.

  • maven() set up the custom repository. In the above example, https://jitpack.io is the custom repository. To add another custom repository, just call maven() again with your custom repository URL.

dependencyResolutionManagement

It configures repositories which your code can download and resolve libraries from. For example, your code uses certain libraries and those libraries' source code is hosted at these repositories.

What are dependencies? Dependencies are libraries that you import as a package in your source code.

  • repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) tells Gradle to fail the build if there are any project-specific repositories. This is to prevent another developer who may fail to build the project if he/she doesn't have the same local repository setup correctly.

  • Same as the plugins, google() set up the maven.google.com repository and mavenCentral() set up repo.maven.apache.org repository. Instead of providing plugin tasks, they provide dependencies (libraries) for your code.

    androidx.*(Android Jetpack libraries) is an example of libraries hosted at google() repository. You probably can't remove mavenCentral() as it is highly coupled with google() repository.

rootProject. name

This is your root project name, which can be any name.

include()

This includes the subprojects/modules that you would like to build. Usually, the app module is pretty common. If you have implemented local libraries, you include them here too.

You can do this

include ("app", "buildutils")

or

include ("app")
include ("buildutils")

build.gradle/build.gradle.kts(root / project)

This defines the core plugins that are used by all your modules.

plugins {
    id("com.android.application") version "7.4.2" apply false
    id("com.android.library") version "7.4.2" apply false
    id("org.jetbrains.kotlin.android") version "1.8.10" apply false
}

In case you do not aware, the functions here are infix notation. It can be rewritten as

plugins {
    id("com.android.application").version("7.4.2").apply(false)
    id("com.android.library").version("7.4.2").apply(false)
    id("org.jetbrains.kotlin.android").version("1.8.10").apply(false)
}

which is a lot more understandable in my opinion.

  • id() - plugin unique id

  • version() - plugin's version

  • apply() - apply this plugin at this project level.

    Usually, you do NOT apply plugins at root project level. You apply the plugins in the module level.

  • com.android.application - plugin to build Android app (e.g. default app module)

  • com.android.library - plugin to build Android library

    This can be removed if you don't build android library but no harm in keeping it here

  • org.jetbrains.kotlin.android - plugin to enable Kotlin support in your project.

gradle. properties (root / project)

"gradle. properties" file is used to define properties and global variables for your Gradle build scripts. Here are some typical examples:

org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
kotlin.code.style=official
android.nonTransitiveRClass=true
  • -Xmx2048m - sets the maximum heap size to 2048M bytes for the Java Virtual Machine

  • Dfile.encoding=UTF-8 - sets the file encoding to UTF-8

  • android.useAndroidX=true - uses the newer Android support library, which is AndroidX

  • kotlin.code.style=official - enforces the "official" Kotlin code style guidelines while compiling and formatting your Kotlin code

  • android.nonTransitiveRClass=true - tells Android build tool to generate non-transitive R classes for your project.

    R class contains references to all the resources (e.g. images, layouts and strings)

    Transitive R class means it includes references to all resources in any libraries/modules that your code depends on.

    Non-transitive R class contains only references to the resources used in your project. Thus, it reduces the app package size significantly.

build.gradle/build.gradle.kts (app module)

This is an example build.gradle/.kts in an app module which consists of plugins {}, android {}, and dependencies {} blocks.

plugins {
    id ("com.android.application")
    id ("org.jetbrains.kotlin.android")
}

android {
    namespace = "vtsen.hashnode.dev.newemptycomposeapp"
    compileSdk = 33

    defaultConfig {
        applicationId = "vtsen.hashnode.dev.newemptycomposeapp"
        minSdk = 21
        targetSdk = 33
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary = true
        }
    }

    buildTypes {
        release {
            isMinifyEnabled  = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                    "proguard-rules.pro")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.4.3"
    }
    packagingOptions {
        resources {
            excludes.add("/META-INF/{AL2.0,LGPL2.1}")
        }
    }
}

dependencies {
    /*...*/
    implementation("androidx.compose.material3:material3:1.1.0-alpha04")
    /*...*/
}

All these blocks (e.g. plugins {}, android {}, dependencies {}, etc) are domain-specify language (DSL) implemented using trailing lambda and function literal with receiver.

plugins {} Block

Similar to the build.gradle/.kts in the root project, this applies plugins in this module. It doesn't need to explicitly call version() because it has already been specified in the root project. apply(true) is also not needed because by default it is true.

android {} Block

This defines the properties specific to the Android platform.

  • namespace - namespace for this project, where all the generated code is based on this namespace.

  • compileSdk - API level is used by Gradle to compile your app(usually the same as targetSdk)

defaultConfig {} Block

This specifies the default configuration for the project.

  • applicationId - Unique ID that is used to identify your app on a device or in Google Play Store.

  • minSdk - Minimum API Level required for the app to run

  • targetSdk - API level the app is designed and tested on (usually the same as compileSdk)

More info on minSdk, targetSdk and compileSdk can be found here:

  • versionCode - an integer value that represents the version of your app

  • versionName - string value that represents the user-visible version of your app. It can be any string but is usually based on <major>.<minor>.<point> version format. It doesn't need to match the version code.

  • testInstrumentationRunner - specify the library to run the instrumented test

  • vectorDrawable - set "useSupportLibrary = true" to enable the vector drawable support for your app

buildTypes {} Block

This allows you to define different build configurations for your app. By default, there are already release and debug build variants. You can override the default by calling the release {} and debug {} within this buildTypes {} block.

When you set up a new project, here are some default override build configurations for the release build variant. Technically you don't need it, I guess it is there for your reference.

  • isMinifyEnabled - when this is set to true, it enables code shrinking and obfuscation (i.e. code optimization) during the build process which reduces the app size.

  • proguardFiles - specifies ProGuard rules files to use to optimize your code during the build process.

    "proguard-android-optimize.txt" is the default code optimization rules specifically for building the android app.

    "proguard-rules. pro" is a custom ProGuard rules that you can apply.

compileOptions {} Block

This specifies options related to compiling your Java code.

  • sourceCompatiblity - specifies the Java version that your code uses.

  • targetCompatiblity - specifies the Java runtime version that your code will be executed on.

kotlinOptions {} Block

This specifies options related to compiling your Kotlin code.

  • jvmTarget - specifies the Java Virtual Machine (JVM) version your code will be compiled for. In short, it compiles your code to byte code that is compatible with the JVM version that you specified.

If you don't specify any compile / Kotlin options here, the default value will be used which could be different for a different version of the build Gradle plugin.

Technically, JVM is for desktop app. For Android app, the runtime is called Dalvik Virtual Machine (DVM) which has been replaced by Android Runtime (ART).

If you are curious about the Kotlin compilation process for Android app, you can read this article.

buildFeatures {} Block

This is specific to the Android build system, which allows you to enable certain features.

  • compose - setting this true enables the Jetpack Compose, which is turned off by default.

composeOptions {} Block

This specifies options related to Jetpack Compose compilation

  • kotlinCompilerExtensionVersion - specifies the compose compiler version

packagingOptions {} Block

This specifies certain resources to exclude from the Android package - APK or Android bundle files.

  • resources - specifies the set of resources that should be processed during the packaging process

    In the above example, it excludes the following license files:

    • */META-INF/AL2.0

    • */META-INF/LGPL2.1

    The purpose is to reduce the Android package file size.

dependencies {} Block

This declares the dependencies/libraries that your code is needed.

  • implementation - specifies the library version that should be included in the Android package (APK/ Android bundle).

If you have unused dependencies in your Android project, it is better to remove them. This can help reduce the size of the Android package (APK/ Android bundle) and improve build times.

Conclusion

Well, build Gradle files seems a bit complex, especially for beginners. If you dig a bit deeper, it is not hard to understand. All the build script examples are taken from this basic Jetpack Compose app template which is the cleanup version of the Empty Compose Activity for the new project generation in Android studio.

Did you find this article valuable?

Support Vincent Tsen by becoming a sponsor. Any amount is appreciated!

ย