Android TOML. Just about dependency directories in Android Studio

Hi all!

My name is Evgeniy and I am an Android developer. Today I would like to share my knowledge and observations regarding a new way of adding dependencies to projects created using Android Studio.

Preface

On February 29, 2024, a new version of Android Studio – Iguana – was released into stable. Along with the change in the version name, it became possible to form dependencies into convenient directories of the format .toml.

Current version of Android Studio

Current version of Android Studio

For me personally, this was a surprise, since this time I did not read about the changes in the new version, and I rarely create projects from scratch; as a rule, I work on already existing projects.

But the surprise was short-lived, after the first look at the dependency block in the new project, it became clear that this could be dealt with and I was already familiar with it. I have already seen such a separation of dependencies in large projects and it was predictable that one day this would become the standard for new projects in Android Studio.

dependencies {
    
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.appcompat)
    implementation(libs.material)
    implementation(libs.androidx.activity)
    implementation(libs.androidx.constraintlayout)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
}

I would like to note that the block for adding dependencies began to look better than it did before.

Let's figure it out

Select any dependency, go to it (ctrl + LKN on Windows and Cmd + LKN on Mac OS) and get into the dependencies directory libs.versions.toml. It looks like this:

On the left we see that libs.versions.toml is located in Gradle Scripts.

On the left we see that libs.versions.toml is located in Gradle Scripts.

The directory contains three sections:

[versions]

[libraries]

[plugins]

From the names it is clear that in the first section you need to specify the version of the dependency or plugin, in the second – dependency for libraries, in the third directory we indicate the dependency for the plugins.

I draw your attention to the fact that we indicate all the necessary data in the format String.

If adding a version of a plugin or library in the section [versions] everything is obvious, the format for adding the dependency itself is not so obvious. I suggest adding the dependency of the room library from the androidx package, first in the old way, and then in the new way.

Adding dependencies

The old way

If we did this the old way, it would look like this:

  1. Adding the KSP annotation processor to build.gradle.kts at the level projectsynchronize the project

plugins {
    alias(libs.plugins.androidApplication) apply false
    alias(libs.plugins.jetbrainsKotlinAndroid) apply false
    id("com.google.devtools.ksp") version "1.8.10-1.0.9" apply false
}
  1. Add a plugin for KSP to build.gradle.kts at the level module (when creating a new project, by default, this is the App module), synchronize the project

    plugins {
        alias(libs.plugins.androidApplication)
        alias(libs.plugins.jetbrainsKotlinAndroid)
        id("com.google.devtools.ksp")
    }
  2. In the dependencies block, we add dependencies for the Room library, an annotationProcessor for working with Room annotations, and the KSP itself for processing them.

    dependencies {
        val room_version = "2.6.1"
    
        implementation("androidx.room:room-runtime:$room_version")
        annotationProcessor("androidx.room:room-compiler:$room_version")
        ksp("androidx.room:room-compiler:$room_version")
        
        implementation(libs.androidx.core.ktx)
        implementation(libs.androidx.appcompat)
        implementation(libs.material)
        implementation(libs.androidx.activity)
        implementation(libs.androidx.constraintlayout)
        testImplementation(libs.junit)
        androidTestImplementation(libs.androidx.junit)
        androidTestImplementation(libs.androidx.espresso.core)
    }

    As we can see, the old way of adding dependencies works fine with the new way.

New way

First, let's look at the new format for adding dependencies.

As we remember from the example above, the old way of adding a dependency in the format

implementation("androidx.room:room-runtime:2.6.1)

Here we see:

implementation – the method itself to which the dependency is added

androidx.room – the package containing the library

room-runtime – name of the library

2.6.1 – library version

It is divided in exactly the same way in the new catalog .toml:

New format diagram for adding dependencies and plugins to .toml

New format diagram for adding dependencies and plugins to .toml

In the diagram we see that in the section [libraries] we added a dependency line for the Room library and its version in the section [versions].

Dependency name – what we call our addiction. The name is arbitrary, it is customary to indicate using kebab-casethat is, through “-” (hyphen or dash).

Next, in functional (curly) brackets we indicate the parameter group – how the dependency will be grouped. Here you need to indicate library package. For example, Room is included in the androix.room package, so we specify it that way. There is no need to put a colon.

Next we indicate the parameter name – This library name.

And lastly, in the parameter version.ref – library version. The very name of the version in the section [versions] it is customary to indicate in camelCase. Let's synchronize the project.

Let's go to build.gradle.kts at the level project and add the KSP plugin (note that in the previous step it was added to [plugins]). Synchronizing the project

plugins {
    alias(libs.plugins.androidApplication) apply false
    alias(libs.plugins.jetbrainsKotlinAndroid) apply false
    alias(libs.plugins.ksp) apply false
}

Let's go to build.gradle.kts at the level module and add the KSP plugin. Let's synchronize the project.

plugins {
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.jetbrainsKotlinAndroid)
    alias(libs.plugins.ksp)
}

In the same file we add the dependencies we need, indicating the path to them in the dependencies block:

dependencies {

    implementation(libs.androidx.room)
    annotationProcessor(libs.androidx.room.annotation.processor)
    ksp(libs.androidx.room.annotation.processor)

I draw your attention to the fact that despite the fact that we added the name of the dependencies in the .toml directory with a hyphen, the path to the files in build.gradle.kts must be added via a dot.

Checking the work:

package com.gorovoyeg.newproject

import androidx.room.ColumnInfo
import androidx.room.Dao
import androidx.room.Database
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.Query
import androidx.room.RoomDatabase

@Database(entities = [TestEntity::class] , version = 1, exportSchema = false)
abstract class TestDatabase: RoomDatabase() {

    abstract fun testDao(): TestDao
}

@Dao
interface TestDao {

    @Query("SELECT * FROM test_entity")
    fun testFunAll(): TestEntity
}

@Entity(tableName = "test_entity")
data class TestEntity(
    @PrimaryKey(autoGenerate = true) val testId: Int,
    @ColumnInfo(name = "test_name" ) val testName: String
)

Everything works perfectly.

Let's sum it up

As I emphasized at the beginning of the article, the innovation of adding dependencies through the libs.versions.toml directory in the new version of Android Studio is a completely obvious and predictable measure on Google’s part. For large ongoing projects, this innovation is no longer relevant, since many already separate dependencies on their own in a more understandable and convenient way than adding dependencies and their versions to the dependencies block in build.gradle. However, I think this is a nice new addition for developers who want to keep their code organized.

Whether to use a new approach or not – I leave the decision to your discretion. Personally I will 🙂

Thank you for your attention.

Similar Posts

Leave a Reply

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