Chapters

Hide chapters

Kotlin Multiplatform by Tutorials

Second Edition · Android 14, iOS 17, Desktop · Kotlin 1.9.10 · Android Studio Hedgehog

1. Introduction
Written by Kevin D Moore

Congratulations! By reading this book, you’re taking the first step toward learning how to write less code. In three sections, you’ll learn how to use Kotlin Multiplatform (KMP) to set up and write iOS, Android and desktop apps using the latest user interface (UI) technologies.

In this book, you’ll develop several different apps — a time zone meeting helper, an app to track your list of things to do and an app that displays a list of all Kodeco’s books, articles and videos.

You’ll learn how to leverage KMP by sharing business logic across platforms and creating customized native UIs in each platform. And, you’ll learn how to write tests for all your business logic, use the popular JetBrains library Ktor to handle network calls and, of course, use Kotlin Coroutines to handle concurrency.

This book requires some knowledge in mobile development but will walk you through the setup for both iOS and Android, as well as for desktop apps. While most of the book uses Kotlin, iOS developers familiar with Swift will be able to pick up Kotlin easily.

In this chapter, you’ll learn about Kotlin Multiplatform and the history of cross-platform frameworks. At the end of the chapter, you’ll set up your environment, create a new project and run your project on Android and iOS.

What Is Kotlin Multiplatform?

Kotlin is a modern and type-safe programming language. It incorporates null safety, preventing many of the dreaded null pointer exceptions that have plagued programming for years. Kotlin also has many innovative features — like data classes and sealed classes, extension functions that let you extend classes with functions outside of the class, lazy loading of variables and many more.

As the name implies, Kotlin Multiplatform uses the Kotlin programming language and works on multiple platforms. Kotlin already works on platforms that support the Java Virtual Machine (JVM), and it uses Kotlin Native for platforms that don’t support the JVM. Kotlin Native compiles Kotlin to native bytecode that runs natively on Apple’s operating systems, Windows and Linux. On the web, KMP compiles Kotlin to JavaScript and HTML.

KMP supports the following platforms:

  • Android
  • iOS
  • macOS
  • watchOS
  • tvOS
  • Windows
  • Linux
  • Web

That’s a lot of platforms. Some, like the web, are not stable at the moment.

KMM

You may have heard the term: Kotlin Multiplatform Mobile (KMM). JetBrains is deprecating this term in favor of Kotlin Multiplatform (KMP) as the technology supports multiple platforms other than mobile alone.

History of Cross-Platform

For as long as there have been both iOS and Android devices, developers have considered the holy grail of app development to be one codebase that could run on both. Many frameworks have tried to achieve multiplatform development, including:

  • PhoneGap: One of the earliest, PhoneGap enabled you to write mobile apps using HTML5, CSS3 and JavaScript. It was discontinued in 2020.
  • Apache Cordova: Open source fork of PhoneGap.
  • Ionic: Uses Angular, React and Vue UI frameworks.
  • Appcelerator Titanium: JavaScript-based SDK that supported iOS, Android, Windows and Blackberry. It was discontinued in 2022 and later open-sourced.

The frameworks above worked by using web technologies to display either native controls or controls designed to look native. However, they suffered from slow JavaScript-to-native communication and had to be updated every time the native platform changed.

  • Xamarin: Microsoft-owned C#-based development framework that includes the .NET runtime. The framework is compiled for iOS — so it’s faster on iOS than on Android, which uses a just-in-time compilation.

  • React Native: Facebook’s mobile-based framework based on the popular React web framework. It’s web- and JavaScript-based. It too has a slow bridge between native and web.

  • Flutter: This is the new kid on the block, and it works on all platforms. One of the main benefits of this framework is that you can write almost all your UI once. Some UI will need to be different based on the platform. For example, desktop and web don’t need a toolbar. One of the disadvantages is that it’s written using the Dart language, which many developers don’t know. Dart has only recently gotten null safety, and a lot of packages use code generation, which has to be done manually.

A lot of the web-based frameworks are falling out of favor. Flutter is going strong, but many question the use of Dart.

History of Kotlin

Kotlin has been around officially since July 2011. JetBrains released version 1.0 on February 15, 2016, and it was announced at Google I/O 2017 as a first-class language for Android development. JetBrains developed Kotlin because most languages didn’t have the features they were looking for. JetBrains now uses Kotlin as its preferred development language for all current work — slowly replacing Java.

Why Kotlin?

Why should you use Kotlin? Because it’s one of the only languages that you can compile for both JVM and native and use on iOS as well as the desktop and web.

Kotlin is ideal for server work as well. With the Ktor library, networking is an easy task. Writing common business logic ensures that all platforms behave the same way and you only need to test once. It uses the same code for all platforms, reducing the possibility of errors and speeding up development. Each team can use as much shared code as they want. Start slowly with existing projects, or start writing all your business logic with new projects.

iOS developers are familiar with Swift, and Kotlin is very similar — so the learning curve should be minimal. Developers still use Swift on the UI side, but they can also work and help out with business logic in Kotlin. Since there will still be a lot of iOS development work needed, iOS developers will be included in all parts of development.

How much code to share is up to the team. If you have an existing app, you can slowly move over your business logic so you have a shared set of code that you can test once.

KMP adds minimal extra size to an app. The standard library is small and you only need to include the parts you use. Lots of apps in the app stores already use it. Many companies find that writing their business logic once — instead of on both iOS and Android — saves the team a lot of time. The UIs are native, making the mobile developers happy, and the users are happy they have a fast experience.

What KMP Is Not

While KMP provides Kotlin as the programming language, it doesn’t provide a UI. If you want to create a UI for Android, you can write it in native code or use the newer Jetpack Compose UI framework. For iOS, you can use UIKit, the newer SwiftUI framework, or the Alpha version of Compose Multiplatform. For the desktop, you can use Desktop Compose or Java Swing. In other words, you have a choice for how you write your UI. Many see this as an advantage — the UI will always be native, so it won’t suffer from the slow bridge communication that web-based frameworks have.

When to Use KMP

One of the nice features of KMP is that you can use as much or as little as you want. If you have an existing app, you can use it for new features or start replacing a feature with KMP. If you start by using KMP for some of the lower layers of your app, you can reuse it for all your platforms. For instance, you can use SQLDelight to replace all your database code with just one set of code. Or, you can write your business logic just once and reuse it on all your platforms. If you need to create code to access networked APIs, you can write it once to work on all platforms.

Layers

Most apps consist of different layers. There’s typically a network layer, a database layer (if needed), a repository layer that interacts with the database, a business logic layer (not always) and a UI layer. KMP doesn’t provide a UI layer; you’ll use the native UI instead.

Business Logic

Most companies now have teams of iOS and Android developers. Each team takes a set of specifications and writes different code to implement those specifications. When testing, each team needs to make sure the logic they’ve implemented works the same as on the other platform. But with two different sets of code, how do they know that all the corner cases work the same way? With one codebase for business logic, both teams can review the code to make sure the logic matches the specifications and know it will work the same for both platforms. With one business logic code base, you can have either both teams work on it together or have one team specialize in writing business logic.

Database

You can write the database layer using SQLite on mobile and desktop using the SQLDelight library. This library is a multiplatform package designed to run on all these platforms. Imagine having to write this set of code only once. Not only will you write only one set of lower-level SQL database insertions, deletions and updates, but your repository layer only needs to be written once. SQLDelight uses SQL statements to generate code for you. You only need to test once.

UI

Since KMP doesn’t provide a UI layer, you can use whichever UI system you want. For iOS, developers are turning to SwiftUI: a nice, declarative UI toolkit that makes it easy to create beautiful UIs. The Alpha version of Compose Multiplatform is available to use on iOS so that you can leverage your knowledge of Compose. Now that Jetpack Compose has been released as stable, Android developers can use it. Cross-platform desktop UIs have been neglected for quite a while. Swing has been a standard for some time, but it’s old and unmaintained. JetBrains hopes to replace it with Compose for Desktop. It uses a lot of Android’s Jetpack Compose underneath, with a layer of desktop code.

Is It Native?

One of the questions most often asked is: Does it use native controls? The answer is yes. Since KMP doesn’t provide any UI layer, all UI is drawn natively. On Android, that can be the built-in View system or the new Jetpack Compose library. On iOS, you can use the built-in native UI, the newer SwiftUI or Compose Multiplatform. On the desktop, you can use the older Java Swing or the newer Desktop Compose. For the Mac desktop, you can also use SwiftUI, AppKit or Compose Multiplatform. For Android, code is generated as Java class files, while iOS uses LLVM to produce native code and create an Xcode framework library.

Current State Of KMP

At the time of writing, KMP is currently in beta, but production apps on both the Google and Apple stores already use it. Since there are multiple layers, here’s the current state of the platform as of the writing of this book:

Fig. 1.1 — KMP Component Status
Fig. 1.1 — KMP Component Status

And:

Fig. 1.2 — KMP Component Status
Fig. 1.2 — KMP Component Status

Since Android apps are built with Kotlin and have been for years, there are no compatibility issues. iOS and macOS apps interact with frameworks built with the KMP system. This will continue to evolve and improve but the feature is still in beta as of this writing. Desktop apps can use the same shared code as the other platforms but use their own UI.

Setting Up Your Environment

You can use either IntelliJ or Android Studio to do KMP work. In this book, you’ll use Android Studio because it seems to work better with mobile platforms at the time of writing.

Downloading Android Studio

Go to https://developer.android.com/studio and download Android Studio Hedgehog edition or later. Once installed, go to Android Studio’s preferences and then to plugins. Search for multiplatform and install the Kotlin Multiplatform Mobile plugin as well as the Compose Multiplatoform IDE Support plugin:

Fig. 1.3 — Android Studio Plugins
Fig. 1.3 — Android Studio Plugins

Restart Android Studio to enable it. Note that Android Studio has a new Beta UI that you can try out.

Existing UI:

Fig. 1.4 — Android Studio Old UI
Fig. 1.4 — Android Studio Old UI

And the new UI:

Fig. 1.5 — Android Studio Old UI
Fig. 1.5 — Android Studio Old UI

Downloading Xcode

To develop for iOS or macOS, you’ll need to install Xcode from the App Store onto your Mac. Make sure you open Xcode to install its tools as well.

Fig. 1.6 — Xcode on the App Store
Fig. 1.6 — Xcode on the App Store

Installing CocoaPods

CocoaPods is a dependency manager for iOS. Since CocoaPods has been around for a long time, it’s easy to use in Xcode and easy to add dependencies. You won’t be using it but if you want to install it, follow the directions below.

If you are on an Intel based Mac, run the following command in Terminal:

sudo gem install cocoapods

The command above installs cocoapods using the default Ruby installation available on macOS.

If you are on an Apple silicon based Mac, run the following command instead:

brew install cocoapods

Verifying Using KDoctor

KDoctor is a tool developed by the Kotlin team to help set up the environment needed to develop apps using KMP.

KDoctor runs a series of checks to verify that Java, Android Studio, Xcode and Cocoapods are correctly installed and configured.

Install KDoctor using the following command:

brew install kdoctor

Once installed, run the following command:

kdoctor

Ensure that all steps are successful. If you had skipped installing Cocoapods in the previous section, the Cocoapods step of KDoctor will fail. This is fine considering that you won’t be using Cocopods for the projects in this book.

In case any other steps fail, KDoctor will provide you with the information needed to fix the issues.

Creating Your First Project

It’s time to create your first project! In Android Studio, open the File menu and choose New ▸ New Project.

Fig. 1.7 — New Project Menu
Fig. 1.7 — New Project Menu

In the New Project window, scroll down to the bottom and choose Kotlin Multiplatform App. If you don’t see this, make sure you installed the Kotlin Multiplatform Mobile plugin. Also, make sure to restart Android Studio after installing the plugin. Click Next.

Fig. 1.8 — New Project Templates
Fig. 1.8 — New Project Templates

In the next dialog, enter the name Find Time and a package name of com.kodeco.findtime or your own package name. Choose the directory you want to store the project and press Next.

Fig. 1.9 — KMP Application Project Dialog
Fig. 1.9 — KMP Application Project Dialog

In the next dialog, leave everything as the default. Here, you’re naming the Android folder androidApp, the iOS folder iosApp, and the shared folder shared. You can use any names you want, but the rest of the book will use these conventions.

KMP now has a “Regular framework” for iOS. This a bit simpler than CocoaPods, so keep “Regular framework”.

Fig. 1.10 — KMP Application Naming Dialog
Fig. 1.10 — KMP Application Naming Dialog

Click Finish, and after a while, a new project will open.

You’ll first see the Android file structure in the left panel, but you want to see all the folders. Choose Project from the menu showing Android. Here, you can see all the folders and files created for you. You have a hidden folder for Gradle and Android Studio (.idea), and the androidApp, gradle, iosApp and shared folders.

Fig. 1.11 — Project View
Fig. 1.11 — Project View

Kotlin Multiplatform Keywords

Now that you have the project created, you need to know about two new keywords that were added to the Kotlin language to support KMP: expect and actual. These let you create classes, functions, interfaces or variables in the shared module using the expect keyword. Those functions or variables aren’t defined in the commonMain folder, but are expected in each multiplatform module — like androidMain or iosMain. expect and actual will be discussed in more detail in a later chapter. If you open the shared folder, you’ll see:

Fig. 1.12 — Shared Module
Fig. 1.12 — Shared Module

Here, you can see folders for Android, common and iOS. You’ll add the shared classes and code to commonMain/kotlin. If you need to write code that is platform specific, you’ll write an expect function or variable in the common folder and the actual code in both the Android and iOS folders. Open the commonMain folder and open Platform.kt.

package com.kodeco.findtime

interface Platform {
    val name: String
}

expect fun getPlatform(): Platform

Here, you see how to use the expect keyword. This says that you expect each platform to have a function named getPlatform that returns a Platform that has a name that is a string. Now, open the Android and iOS Platform.kt files.

Android

Open androidMain/kotlin/com/kodeco/findtime/Platform.android.kt.

package com.kodeco.findtime

class AndroidPlatform : Platform {
    override val name: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}

actual fun getPlatform(): Platform = AndroidPlatform()

In the Android class, the new keyword actual states that this is the actual implementation for the expected getPlatform function. The name variable overrides the name variable and provides an implementation for the variable to return the string “Android” and the Android SDK number.

Run the Android app from Android Studio by making sure you have the androidApp selected in the toolbar and an emulator or phone selected. Then, click the green Play button.

Fig. 1.13 — Run Configuration
Fig. 1.13 — Run Configuration

Note: If you get a build error about shared test files, open up shared/build.gradle.kts and comment out the commonTest section.

You’ll see:

Fig. 1.14 — Android app running
Fig. 1.14 — Android app running

Your screen now shows the words Hello, Android and the Android version.

iOS

Open Platform.ios.kt in shared/src/iosMain/kotlin/com/kodeco/findtime:

package com.kodeco.findtime

import platform.UIKit.UIDevice

class IOSPlatform: Platform {
    override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}

actual fun getPlatform(): Platform = IOSPlatform()

Notice that this class is written in Kotlin but uses iOS platform code. Wow, you can write iOS code in Kotlin! When you build your project, the KMP plugin will compile this class into a framework. Open Xcode. From the File menu, choose Open and navigate to your project and into the iosApp folder. Select the workspace file (iosApp.xcworkspace).

Fig. 1.15 — XCode Open Project
Fig. 1.15 — XCode Open Project

For the project to run without errors, you’ll need to build in Xcode. Select ProductBuild or press Command-B. Once the project is built, open ContentView.swift.

import SwiftUI
import shared

struct ContentView: View {
	let greet = Greeting().greet()

	var body: some View {
		Text(greet)
	}
}

struct ContentView_Previews: PreviewProvider {
	static var previews: some View {
		ContentView()
	}
}

This file has been generated for you and is written in SwiftUI. You’ll get a crash course in SwiftUI in a later chapter. Hover over greet(), press Command-Control and click to jump to its definition.

Fig. 1.16 — Xcode method definition
Fig. 1.16 — Xcode method definition

This will open the shared.h file. It’s written in Objective-C, but it allows you to use all the code from the shared project. Scroll to the bottom of the file and you will see:

__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("Greeting")))
@interface SharedGreeting : SharedBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
- (NSString *)greet __attribute__((swift_name("greet()")));
@end

Run the app in a simulator in Xcode by clicking Play or by pressing Command-R. You’ll see:

Fig. 1.17 — iOS app running
Fig. 1.17 — iOS app running

The screen now shows the code written in Kotlin using the device name and the device version.

Key Points

  • KMP refers to Kotlin Multiplatform.
  • KMP helps write common code for networking, database and business logic.
  • You can’t use KMP for UI work. You’ll need to use native frameworks instead.
  • It’s easy to create a KMP project for mobile by using the Kotlin Multiplatform Mobile plugin.

Where to Go From Here?

In this chapter, you’ve learned a bit about KMP.

To learn more about Kotlin:

In the next chapter, you’ll build on this project to create the Find Time project.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.