How to create a Kotlin Multiplatform library?

iteo
5 min readDec 19, 2023

After hours, I extensively experimented with a platform for storing and sharing code snippets which required a syntax highlighting component used in many places and in various scenarios. Nonetheless, most of the existing libraries worked well only in one scenario and needed a different solution for each platform.

It urged me to start writing my own engine for syntax analysis and coloring, which, among other things, became a part of the SnippLog project. However, there was so much code that it would be a shame to keep it hidden, so I embarked on creating a library.

But first, let me dive into some basics to then tackle the main topic.

What is Kotlin Multiplatform?

Kotlin Multiplatform is an experimental feature of Kotlin that allows developers to use the same codebase for different platforms, be it iOS, Android, Web, Desktop, or even backend services. It’s a continuation of Kotlin’s philosophy of interoperability: you write Kotlin code that is then compiled to the appropriate format for each platform (e.g., JVM bytecode for Android, JavaScript for the web, or native binary for iOS).

Why Kotlin Multiplatform?

  • Code Reuse: With KMP, common logic like data processing, business rules, or network communication can be written just once and shared across platforms, reducing redundancy.
  • Maintainability: Fewer codebases mean reduced maintenance effort. Bugs need to be fixed in one place, and features can be added consistently across platforms.
  • Platform-Specific Code Stays Platform-Specific: While the common logic is shared, KMP allows developers to write platform-specific code whenever necessary. This means applications can still utilize platform-specific features or APIs to provide the best user experience.
  • Seamless Integration: Kotlin Multiplatform projects can easily integrate with existing Android, iOS, or Web projects. This makes migration more gradual and less risky.

How Does It Work?

  1. Common Module: This is where the shared Kotlin code resides. It doesn’t contain any platform-specific dependencies.
  2. Platform Modules: For each target platform, there’s a corresponding module. This is where you’d place any platform-specific code or dependencies. For instance, while the networking logic might be shared, the actual HTTP client implementation might be different on Android and iOS.
  3. Expect/Actual Mechanism: One of the cornerstones of KMP. In the common module, you define expect declarations, which are like promises that you’ll provide implementations in each platform module. In the platform modules, you then provide the actual implementations.

Creating a Kotlin Multiplatform library step by step

1. Creating a JVM project

Generally speaking, to create a multiplatform library in Kotlin, you need to create a JVM project and add a few building blocks.

Most of the configuration boils down to editing the main build.gradle.kts file.

We add to the plugins or switch to the multiplatform variant. Then, it’s necessary to create a Kotlin section.

plugins {
kotlin("multiplatform") version "1.9.0"
}
kotlin {
// Targets

// Source Sets
}

And here’s the first piece of advice. The version of the chosen Multiplatform plugin affects the language version, and often the IDE as well. I suggest updating all dependencies and tools to the latest version right from the start before diving into code writing.

To ensure all dependencies can be properly fetched, add a few more things in settings.gradle.kts:

pluginManagement {
repositories {
google()
gradlePluginPortal()
mavenCentral()
}
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
rootProject.name = "highlights"

2. Code base

The folder structure depends on which platforms we are writing independent code for. In this case, the goal was to create a project in pure Kotlin which required only two folders:

  • commonMain — source code without typical platform-specific dependencies
  • commonTest — tests ready to be run in a JVM environment

If there’s a need for specific implementations, you should subsequently define iosMain, androidTest, and linuxMain.

3. Targets

Even though the code is ready to use regardless of the environment, each of the target platforms needs to be defined manually.

kotlin {
      // Android
jvm {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
withJava()
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
// iOS
iosX64()
iosArm64()
iosSimulatorArm64()
// Desktop
mingwX64()
linuxX64()
linuxArm64()
macosX64()
macosArm64()
// Web
js {
browser()
nodejs()
}

...
}

Pro tip: There are aggregating variants such as ios() or android() which allow you to optimize the code a bit. For each variant, a jar, pom, and all the metadata that a library should have will be generated. When you implement dev.snipme.highlights in a project, the source, for example, dev.snipme.highlights-iosarm64 or dev.snipme.highlights-jvm, will be automatically pulled. Therefore, it’s important to publish all the artifacts you intend to support with your library.

4. SourceSets

Similarly, when you import one of the multiplatform libraries into commonMain, the system will automatically find the corresponding artifact, so you don’t have to worry about it.

Even in such a simple project, I needed to use a Kotlin testing library. The import looks like this:

kotlin {

...

sourceSets {
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
}

}

However, it might happen that the creator did not publish the project in the form of Kotlin Multiplatform, and in such a case, you should rely on dependencies per architecture. Then, you can specify for which compilation you’re using the dependency and simply define it:

sourceSets {

...

val androidMain by getting {
dependencies {
implementation("androidx.activity:activity-compose:1.7.2")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.core:core-ktx:1.10.1")
}
}
}

Kotlin Multiplatform is currently supported by many projects, so I suggest first trying to use the general variant of the library in commonMain.

5. Publication to Maven Central

There are many articles available on this topic. Many are written for Java alone, but you can also find ones focused on modern Kotlin. For this, I recommend simply following the official guides on the JetBrains website. They are up-to-date, precise, and comprehensive on the subject. When it comes to publishing a library, this article is probably one of the best.

Summing up

After some effort, I managed to publish my first library on Maven Central, and it’s even multi-platform! It’s an open-source tool for analyzing and syntax highlighting. With it, you can break down a piece of code into its fundamental parts and additionally color it.

Hope these tips will help you navigate the still somewhat chaotic world of Kotlin Multiplatform and KMM. Enjoy!

PS. Remember that KMP is evolving very dynamically, and the solutions were up-to-date at the time of writing the article.

--

--

iteo

iteo is an international digital product studio founded in Poland, that helps businesses benefit from technology better. Visit us on www.iteo.com