Libraries & Plugins

Libraries & Plugins

This section describes how to install and maintain your project dependencies i.e. plugins and libraries.

Overview

Dependencies refers to plugins and libraries that you can add to your project. Kotlin has the ability to use both Java libraries and specific Kotlin libraries. The following are curated lists of useful libraries and plugins:

  • KLibs.io is a JetBrains search engine for KMP (multiplatform) libraries. Highly recommended.
  • Awesome KMM is a curated list of community-contributed libraries.
ℹ️
Be aware that libraries may be specific to a particular platform e.g., some libraries are Android only, some are desktop/JVM. Whenever possible, you should look for Kotlin-first, KMP libraries. KMP stands for Kotlin Multiplatform, meaning that it will run anywhere and has no native dependencies.

Libraries

Libraries are packaged modules that you can import and use in your project. In Kotlin, a great deal of required functionality e.g., networking, user interfaces, is pushed into libraries. Before building anything ‘from scratch’, you should first check if there’s a suitable library to handle it.

Installation

From the search engines above, you will be directed to a library details page, which includes information on how to install and use it in your project.

Coil details
https://klibs.io/project/coil-kt/coil
Coil installation
https://klibs.io/project/coil-kt/coil

To install a library, add the dependencies entry from the library details screen to the appropriate build.gradle.kts file.

For example, adding coil would result in a build.gradle.kts with this information.

repositories {
     mavenCentral()
}

dependencies {
    implementation("io.coil-kt.coil3:coil-compose:3.1.0")
    implementation("io.coil-kt.coil3:coil-network-okhttp:3.1.0")
}

The implementation keyword indicates that this dependency is required for the application to both compile and run. There are other keywords that can be used to specify different types of dependencies e.g.,

  • runtimeOnly for dependencies that are only required at runtime.
  • testImplementation for dependencies that are only required for testing.
  • api when writing libraries, to indicate that transitive dependencies need to be exported (i.e. the libraries that your dependencies require).

You should use implementation for most dependencies.

⚠️
Please read documentation carefully and make sure to use the most recent version of a library. I strongly recommend testing a library against a small sample project before fully committing to it.

Core Libraries

These are core libraries that you include in every project.

JetBrains libraries

These are official libraries supported by JetBrains. You will include these as-needed.

Third-Party Libraries

These libraries are released and supported by the community, which cover everything else! We only list libraries that claim to be multiplatform, meaning that they will run on Android, Desktop, or any supported platform.

  • Appdirs: Find special folders for your platform e.g., Windows Pictures folder.
  • Clickt: Command-line interface framework. Used for console apps only.
  • Coil: Image loading library, uses coroutines.
  • Compose Rich Text Editor: Jetpack Compose and Compose Multiplatform editor library.
  • File Picker: Compose multiplatform file picker.
  • Keval: A Kotlin mini library for math expression string evaluation.
  • Ksoup: Kotlin multiplatform HTML/XML parser. Port of Jsoup to Kotlin.
  • kubriko: KMP and Compose multiplatform 2D game engine(!).
  • Multiplatform Settings: Multiplatform key:value storage.
  • Okio: Multiplatform IO library. Useful for working with byte streams.
  • PDFBox: Java library fork working with PDF files.
  • Room: KMP database library for SQLite.
  • SQLDelight: Database integration. Alternative to Exposed for Android.
  • Voyager: Navigation library. Alternative to Odyssey. See Meet Voyager.

Plugins

Plugins extend Gradle’s functionality by adding new build tasks or build configuration steps. It’s unlikely that you will need to add any plugins in this course, but a few of these might be helpful if you require help debugging your build, tracing a strange dependency error etc.

Installation

From a plugin project page, you should be able to locate the installation information. Plugin configuration information is typically added to the build.gradle.kts file for your project.

For example, this plugin statement would import the lumo plugin.

plugins {
    id ("com.nomanr.plugin.lumo") version "1.2.5"
}

Community Plugins

Community plugins that can extend your build’s functionality. Search the Gradle plugin portal.

  • Dependency Analysis can analyze your dependencies and locate errors in config files. Use this if you get strange dependency errors!
  • lumo-ui: customizable Ul components for Compose (plugin, not a library!)
  • Shadow is a plugin for creating fat/uber JARs. Useful for creating standalone console applications. This is not recommended for Android or Compose projects.

Version Catalogs

The biggest challenge of working with libraries and plugins is keeping track of which versions you should be using. Often you need specific versions of libraries in order for them to work together. You might also need to have a library imported into multiple projects – how do you make sure that you are using a consistent version there?

There are many ways to approach this e.g., hard-coding variables in the gradle.properties file. The recommended approach is to use a version catalogs: a centralized file that contains a list of libraries and their versions.

Creating a Catalog

In Gradle 7.6 or later, the version catalog is contained in a file named libs.versions.toml in your gradle project directory.

A version catalog file contains sections for versions, libraries (dependencies) and plugins. Notice that the module name is the URL that we used earlier, with the version number stripped out.

[versions]
kotlin-version = "2.0.20-RC"
serialization-version = "1.9.0"
clikt-version = "4.4.0"
ktor-version = "2.3.4"
ktor-api-version = "2.2.4"
json-version = "1.7.1"
slf4j-version = "2.0.7"
versions-version = "0.51.0"

[libraries]
clikt = { module = "com.github.ajalt.clikt:clikt", version.ref = "clikt-version" }
ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-version"}
ktor-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor-version"}
ktor-server = { module = "io.ktor:ktor-server-default-headers", version.ref = "ktor-version"}
ktor-api = { module = "dev.forst:ktor-api-key", version.ref = "ktor-api-version" }
json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "json-version" }
slf4j = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j-version"}

[plugins]
ktor = { id = "io.ktor.plugin", version.ref = "ktor-version" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-version" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "serialization-version" }
versions = {id = "com.github.ben-manes.versions", version.ref = "versions-version" }

To create a version catalog,

  1. Create a file named libs.versions.toml in the gradle directory in the root of your project.
  2. Add sections for [versions], [libraries] and [plugins] as above.
  3. Add entries for each of your libraries that you need to add. Follow the conventions above.

Referencing the Catalog

In build.gradle.kts, we can use these library names to refer to specific libraries and versions.

dependencies {
plugins {
    // different forms of the same plugin declaration

    // kotlin("jvm") version "1.9.10"
    // id("org.jetbrains.kotlin.jvm") version "1.9.10"
    alias(libs.plugins.kotlin.jvm) // core kotlin

    // kotlin("plugin.serialization") version "1.9.0"
    // id("org.jetbrains.kotlin.plugin.serialization") version "1.9.0"
    alias(libs.plugins.kotlin.serialization) // json-serialization

    alias(libs.plugins.ktor) // provides networking support
    alias(libs.plugins.versions) // checks versions, see help > dependencyUpdates
}

group = "ca.uwaterloo"
version = "1.2"

application {
    mainClass.set("ca.uwaterloo.ApplicationKt")
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(libs.json)
    implementation(libs.clikt)
    implementation(libs.slf4j)

    implementation(libs.ktor.cio)
    implementation(libs.ktor.core)
    implementation(libs.ktor.server)
    implementation(libs.ktor.api)
}

Final Word

XKCD Dependency
https://xkcd.com/2347