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 raywenderlich.com’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.
KMP vs. KMM
You use KMP to write code using Kotlin for multiple platforms. Kotlin Multiplatform Mobile (KMM) is a way to use Kotlin specifically for cross-platform mobile development. When you’re talking about developing just for mobile devices, you’re talking about KMM — but if you’re talking about all platforms, including desktop or the web, you’re talking about KMP.
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. Discontinued and will be open-sourced by March 2022.
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 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.
KMM: KMM, while newer, has become very popular. 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 or the newer SwiftUI framework using Swift. 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 and KMM 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 KMM 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. 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. Currently, there’s an issue with package names with Android using androidx and desktop using org.jetbrains. JetBrains hope to resolve this in the future.
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 or the newer SwiftUI. On the desktop, you can use the older Java Swing or the newer Desktop Compose. For the Mac desktop, you can also use SwiftUI or AppKit. 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 alpha, 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:
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 KMM system. This will continue to evolve and improve but the feature is still in beta. 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.
Download Android Studio
Go to https://developer.android.com/studio and download Android Studio Bumblebee 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:
Restart Android Studio to enable it.
Download Xcode
If you want 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.
Install 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.
If you are on an Intel based Mac, run the following command in Terminal on your Mac:
sudo gem install cocoapods
The command above installs cocoapods using the default Ruby installation available on macOS.
If you are on an M1 based Mac, run the following command in Terminal on your Mac:
brew install cocoapods
Creating your first project
It’s time to create your first project! In Android Studio, open the File menu and choose New ▸ New Project.
In the New Project window, scroll down to the last entry and choose Kotlin Multiplatform App. If you don’t see this, make sure you installed the KMM plugin. Also, make sure to restart Android Studio after installing the plugin. Click Next.
In the next dialog, enter the name Find Time and a package name of com.raywenderlich.findtime or your own package name. Choose the directory you want to store the project and press Next.
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.
As mentioned earlier, you’ll use the CocoaPods dependency manager for iOS. When the Gradle files are created, Android Studio will add a section for CocoaPods.
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.
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 functions 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. If you open the shared folder, you’ll see:
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.raywenderlich.findtime
expect class Platform() {
val platform: String
}
Here, you see how to use the expect keyword. This says that you expect each platform to have an actual class named Platform that implements this class and has a variable named platform that is a string. Now, open the Android and iOS Platform.kt files.
Android
package com.raywenderlich.findtime
actual class Platform actual constructor() {
actual val platform: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}
In the Android class, the new keyword actual states that this is the actual implementation for the expected Platform class. The platform variable also has the actual keyword 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.
You’ll see:
Your screen now shows the words Hello, Android and the Android version.
For iOS, open Platform.kt in shared/src/iosMain/kotlin/com/raywenderlich/findtime:
package com.raywenderlich.findtime
import platform.UIKit.UIDevice
actual class Platform actual constructor() {
actual val platform: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}
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). For the project to run without errors, you’ll need to build in Xcode. Select Product ▸ Build or press Command-B. Once the project is built, open ContentView.swift.
import SwiftUI
import shared
struct ContentView: View {
let greet = Greeting().greeting()
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 greeting() and press Command-Click.
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:
public class Greeting : KotlinBase {
public init()
open func greeting() -> String
}
public class Platform : KotlinBase {
public init()
open var platform: String { get }
}
Run the app in a simulator in Xcode by clicking Play or by pressing Command-R. You’ll see:
The screen now shows the code written in Kotlin using the device name and the device version.
Key points
- KMP refers to Kotlin Multiplatform, and KMM refers to Kotlin Multiplatform Mobile.
- 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 by using the KMM plugin.
Where to go from here?
In this chapter, you’ve learned a bit about KMP and KMM.
- If you want to learn more, go to https://kotlinlang.org/docs/multiplatform.html
- For the latest in what’s new with KMM, go to https://kotlinlang.org/docs/mobile/whats-new-in-kotlin-for-kmm.html.
- To find the current state of each platform, go to https://kotlinlang.org/docs/mobile/kmm-evolution.html.
- To see some of the top companies using KMP, go to https://medium.com/@touchlab/top-8-mobile-apps-in-2020-built-with-kotlin-multiplatform-3e9fea10e2af and https://kotlinlang.org/lp/mobile/case-studies/.
To learn more about Kotlin:
-
raywenderlich.com Learning Paths at https://www.raywenderlich.com/android/paths/learn
-
Kotlinlang Docs at https://kotlinlang.org/docs/home.html
In the next chapter, you’ll build on this project to create the Find Time project.