Blog Infos
Author
Published
Topics
,
Author
Published
Topics
,

Image from Jetbrains blog article

 

Many of us have faced Groovy difficulties and used to convert it to Kotlin DSL. Then, as Android engineers, working on a project entirely written in Kotlin is pure joy.

We assume going on a feature-based modularized app structure applying the version catalog feature. We would adequately manage the build logic to make it centralized and reusable by the modules.
Here are the steps to facilitate your Gradle build configurations into a centralized build logic by creating your convention plugin scripts.

The typical way we all used was to place the custom scripts into the default buildSrc module. Previously, buildSrc implementation was not recommended because of invalidating the build cache and synchronizing the whole project with every change to the dependencies.
It’s now treated as an included build in Gradle 8.

Project level declaration

In the project settings script, we move the configuration scripts into a build-logic composite build module.
The first pluginManagement block ensures Gradle uses suitable repositories for the plugins. We include our new module in the build and specify explicitly the repositories we need.
Another key element is the mode in the centralized dependency declarations that you would declare to enforce Gradle always to get the correct dependencies regarding the resolution mode. In this example, we would use the repositories stated in the project settings.

@file:Suppress("UnstableApiUsage")
enableFeaturePreview("VERSION_CATALOGS")
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
pluginManagement {
includeBuild("build-logic")
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "GradleKotlinConventionPlugins"
include(":app")

Project level settings script

 

Shared logic composite module

We start the new composite module by enabling the version catalog feature in the settings script.

@Suppress("UnstableApiUsage")
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "build-logic"

Build logic module settings script

 

Now, we define our new module as a Kotlin script by enabling the Kotlin DSL and forcing the precompiled script plugins to make it part of the Kotlin source set like any other class.
Henceforth, the composite module as part of the project build is responsible for the configuration, which we usually do in the project-level Gradle build script. We move there the Gradle-specific declarations.

plugins {
`kotlin-dsl`
`kotlin-dsl-precompiled-script-plugins`
}
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
dependencies {
implementation(libs.kotlin.gradlePlugin)
implementation(libs.gradle)
}
tasks.test {
useJUnitPlatform()
}

Build logic module build script

Type-based conventions

In a feature-based modularized app structure, we have the main app module, the feature modules, and the shared modules for some reusable logic or data, for example.

The main convention plugins we identify :

  • Kotlin library convention
  • Android library convention
  • Android composable library convention
Kotlin library convention

Kotlin library convention is a plugin we usually use to declare some APIs or to share some logic. It is an overridden Java library where we target the JDK version.

plugins {
`java-library`
kotlin("jvm")
}
kotlin {
jvmToolchain(jdkVersion = 11)
}
task("testUnitTest") {
dependsOn("test")
}

Kotlin library conventions plugin script

Kotlin Android library convention

Kotlin Android library convention is applied by the feature modules with ViewBinding feature activated by default.

plugins {
id("com.android.library")
kotlin("android")
}
@Suppress("UnstableApiUsage")
android {
. . .
compileOptions {
isCoreLibraryDesugaringEnabled = true
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
buildFeatures {
viewBinding = true
}
}
dependencies {
. . .
}

Kotlin Android library conventions plugin script

Job Offers

Job Offers


    Developer Relations Engineer

    Embrace
    United States
    • Full Time
    apply now

    Android Team Lead

    Komoot
    Remote EMEA
    • Full Time
    apply now

    Information Security Engineer

    MongoDB
    London, UK
    • Full Time
    apply now

OUR VIDEO RECOMMENDATION

, ,

Keynote: Kotlin and the Multiplatform Future

While Kotlin started on the JVM, and subsequently gained adoption in the Android community, it has evolved into a language that supports many platforms. Kotlin Multiplatform has emerged as a technology that allows us to…
Watch Video

Keynote: Kotlin and the Multiplatform Future

Hadi Hariri
Never believed in elevator pitches

Keynote: Kotlin and the Multiplatform Future

Hadi Hariri
Never believed in el ...

Keynote: Kotlin and the Multiplatform Future

Hadi Hariri
Never believed in elevato ...

Jobs

Kotlin Android composable library convention

It is an extension of the previous library convention with the Jetpack Compose-related declarations.

plugins {
id("kotlin-android-library-conventions")
}
@Suppress("UnstableApiUsage")
android {
buildFeatures.compose = true
composeOptions.kotlinCompilerExtensionVersion = libs.versionKotlinCompiler
}
dependencies {
implementation(platform(libs.libAndroidxComposeBom))
implementation(libs.libAndroidxComposeFoundation)
}

Kotlin Android library conventions with Jetpack Compose plugin script

When we create a new module, it is much easier to define the build script by applying the convention plugins and the additional dependencies.
We could also consider applying the composite module to another project.

plugins {
id("kotlin-android-library-conventions")
id("test-conventions")
}
dependencies {
implementation(libs.androidX.appCompat)
implementation(libs.google.material)
}

Sample feature build script applying custom convention plugins

Conclusion

In conclusion, modularization is our main concern for the ever-growing projects to solve many problems we can enumerate: codebase size, scalability, readability, code quality, code duplication, etc.
We usually and naturally split the project into feature-oriented modules by isolating the feature code.
Google Android team has also recently published a guide to app modularization with the same approach.

There are some constraining issues related to Version Catalog.
The libraries are not directly accessible, and we need to create some extension functions to solve it.
And the plugins are not recognized in the plugins block. The issue seems fixed in Gradle 8.

You can find all of the source code in my Github conventions repository here.

This article was previously published on proandroiddev.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
Hi, today I come to you with a quick tip on how to update…
READ MORE
blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu