Kotlin Multiplatform Mobile (KMM): Building Apps for iOS and Android

This tutorial will guide you through the process of building mobile apps for both iOS and Android using Kotlin Multiplatform Mobile (KMM). Kotlin Multiplatform Mobile is a cross-platform development solution that allows developers to write shared code in Kotlin and target multiple platforms, including iOS and Android. This tutorial will cover the advantages of using KMM, the setup process, developing for iOS and Android, sharing code, and building and deploying the apps.

kotlin multiplatform mobile building apps ios android

Introduction

What is Kotlin Multiplatform Mobile (KMM)?

Kotlin Multiplatform Mobile (KMM) is a framework that enables developers to write shared code in Kotlin and use it across multiple platforms, including iOS and Android. With KMM, developers can save time and effort by reusing code and business logic between different mobile platforms, reducing the need for separate codebases. KMM provides a seamless integration between Kotlin and native platform-specific code, allowing developers to leverage the full power of each platform while maintaining code consistency.

Advantages of using KMM

There are several advantages to using Kotlin Multiplatform Mobile for building mobile apps:

  1. Code Reusability: KMM allows developers to write shared code in Kotlin that can be used across multiple platforms, eliminating the need for separate codebases for iOS and Android. This significantly reduces development time and effort.

  2. Native Performance: KMM provides a seamless integration between Kotlin and native platform-specific code, allowing developers to leverage the performance and capabilities of each platform. This ensures that the apps developed with KMM have native-like performance and user experience.

  3. Easy Maintenance: With KMM, developers can maintain a single codebase for both iOS and Android, reducing the complexity and effort required for maintenance. Changes and updates can be implemented once and applied to both platforms simultaneously.

  4. Community Support: Kotlin Multiplatform Mobile is backed by JetBrains, the creators of Kotlin, and has a vibrant and growing community of developers. This ensures that developers have access to resources, libraries, and support when building apps with KMM.

Comparison with other cross-platform frameworks

Kotlin Multiplatform Mobile offers several advantages over other cross-platform frameworks like React Native, Flutter, and Xamarin:

  • React Native: While React Native also allows code sharing between iOS and Android, it uses JavaScript, which can lead to performance and integration issues. KMM, on the other hand, uses Kotlin, a statically-typed language that seamlessly integrates with native platform-specific code.

  • Flutter: Flutter uses its own UI framework, which requires learning a new set of widgets and UI concepts. KMM, on the other hand, allows developers to build the UI using the native platform-specific UI frameworks, such as SwiftUI for iOS and Jetpack Compose for Android.

  • Xamarin: Xamarin uses C# for cross-platform development, which requires learning a new language and ecosystem. KMM, on the other hand, uses Kotlin, a language that is already widely adopted by Android developers.

Setting Up KMM

Installing Kotlin and KMM plugin

Before getting started with KMM, you will need to install Kotlin and the KMM plugin in your development environment. Follow the steps below to set up your environment:

  1. Install Kotlin: Kotlin can be installed using the Kotlin command-line compiler (kotlinc) or by installing the Kotlin plugin for your IDE. Visit the official Kotlin website for detailed installation instructions.

  2. Install KMM Plugin: Install the KMM plugin for your IDE. The plugin provides support for creating and managing KMM projects. Consult the documentation of your IDE for instructions on installing plugins.

Creating a new KMM project

Once you have installed Kotlin and the KMM plugin, you can create a new KMM project. Follow the steps below to create a new KMM project:

  1. Open your IDE and select the option to create a new project.

  2. Choose the Kotlin Multiplatform Mobile template and provide a name for your project.

  3. Configure the project settings, such as the project location and platform-specific configurations.

  4. Click "Finish" to create the project.

Configuring shared and platform-specific code

After creating the project, you will have a shared module that contains the shared code and platform-specific modules for iOS and Android. The shared module is where you will write the shared business logic, while the platform-specific modules are where you will write code specific to each platform.

To configure the shared and platform-specific code, follow these steps:

  1. Open the project structure or settings in your IDE.

  2. Navigate to the module settings and select the shared module.

  3. Add the desired platform-specific modules as dependencies to the shared module.

  4. Configure the build settings for each module to include the shared code.

Developing for iOS

Creating iOS-specific UI

To create iOS-specific UI in your KMM project, you can use SwiftUI, Apple's declarative UI framework. SwiftUI allows you to define the UI using a concise and expressive syntax. Here's an example of creating a simple SwiftUI view in your KMM project:

import SwiftUI

class ContentView: View {
    var body: some View {
        Text("Hello, iOS!")
            .font(.largeTitle)
            .foregroundColor(.blue)
    }
}

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

In this example, we define a ContentView class that conforms to the View protocol. The body property defines the UI of the view, which consists of a Text element displaying the text "Hello, iOS!". We also set the font size to .largeTitle and the text color to .blue.

The ContentView_Previews struct provides a preview of the view, allowing you to see how it will look in different environments.

Accessing iOS frameworks and APIs

KMM provides seamless integration with iOS frameworks and APIs, allowing you to access platform-specific functionality in your shared code. To access iOS frameworks and APIs, you can use the expect and actual declarations.

Here's an example of accessing the UIKit framework in your shared code:

expect class UIApplication {
    fun openURL(url: NSURL)
}

actual class UIApplication {
    actual fun openURL(url: NSURL) {
        // Call the iOS-specific implementation
        UIApplication.shared.openURL(url)
    }
}

In this example, we declare an UIApplication class with an openURL function using the expect keyword. This declares the function signature in the shared code.

In the actual implementation, we provide the platform-specific implementation for iOS using the actual keyword. In this case, we call the openURL function of the UIApplication singleton.

Testing and debugging on iOS devices

To test and debug your KMM app on iOS devices, you can use the Xcode IDE. Follow these steps to test and debug your app on an iOS device:

  1. Connect your iOS device to your computer using a USB cable.

  2. Open the Xcode project for the iOS module of your KMM project.

  3. Select your iOS device as the target device in Xcode.

  4. Build and run the app on your iOS device.

You can use the Xcode debugger to set breakpoints, inspect variables, and step through your code for debugging purposes.

Developing for Android

Creating Android-specific UI

To create Android-specific UI in your KMM project, you can use Jetpack Compose, Google's modern UI toolkit for building native Android apps. Jetpack Compose allows you to define the UI using a declarative syntax. Here's an example of creating a simple Jetpack Compose UI in your KMM project:

import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Column
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.setContent
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun ContentView() {
    MaterialTheme {
        Column {
            Text(text = "Hello, Android!", style = MaterialTheme.typography.h1)
        }
    }
}

@Preview
@Composable
fun ContentViewPreview() {
    ContentView()
}

In this example, we define a ContentView function using the @Composable annotation. The function defines the UI of the view using Jetpack Compose components. In this case, we have a Text component displaying the text "Hello, Android!" with a heading style.

The ContentViewPreview function provides a preview of the view using the @Preview annotation.

Accessing Android frameworks and APIs

KMM allows you to access Android frameworks and APIs in your shared code using the expect and actual declarations. Here's an example of accessing the SharedPreferences API in your shared code:

expect class SharedPreferences {
    fun getString(key: String, defaultValue: String): String?
    fun putString(key: String, value: String)
}

actual class SharedPreferences {
    actual fun getString(key: String, defaultValue: String): String? {
        // Call the Android-specific implementation
        return PreferenceManager.getDefaultSharedPreferences(context).getString(key, defaultValue)
    }

    actual fun putString(key: String, value: String) {
        // Call the Android-specific implementation
        PreferenceManager.getDefaultSharedPreferences(context).edit().putString(key, value).apply()
    }
}

In this example, we declare a SharedPreferences class with getString and putString functions using the expect keyword. This declares the function signatures in the shared code.

In the actual implementation, we provide the platform-specific implementation for Android using the actual keyword. In this case, we call the corresponding SharedPreferences methods using the PreferenceManager class.

Testing and debugging on Android devices

To test and debug your KMM app on Android devices, you can use Android Studio. Follow these steps to test and debug your app on an Android device:

  1. Connect your Android device to your computer using a USB cable.

  2. Open the Android module of your KMM project in Android Studio.

  3. Select your Android device as the target device in the device selector.

  4. Build and run the app on your Android device.

You can use the Android Studio debugger to set breakpoints, inspect variables, and step through your code for debugging purposes.

Sharing Code

One of the key benefits of Kotlin Multiplatform Mobile is the ability to share code between different platforms. In this section, we will explore how to write shared business logic, share data models and networking code, and handle platform-specific dependencies.

Writing shared business logic

To write shared business logic in your KMM project, you can create shared Kotlin classes and functions that can be used by both iOS and Android. Here's an example of a shared Calculator class that performs basic arithmetic operations:

class Calculator {
    fun add(a: Int, b: Int): Int {
        return a + b
    }

    fun subtract(a: Int, b: Int): Int {
        return a - b
    }
}

In this example, we define a Calculator class with add and subtract functions that perform addition and subtraction operations. This class can be used by both iOS and Android code.

Sharing data models and networking code

KMM allows you to share data models and networking code between iOS and Android. Here's an example of a shared User data class and a shared networking function that fetches user data:

data class User(val id: String, val name: String, val email: String)

expect suspend fun fetchUser(id: String): User

actual suspend fun fetchUser(id: String): User {
    // Perform the networking request and parse the response
    val response = httpClient.get("https://api.example.com/users/$id")
    return response.toUser()
}

In this example, we declare a User data class using the data class keyword. This class represents a user object with id, name, and email properties.

We also declare a fetchUser function with the expect keyword. This function fetches user data from a remote API and returns a User object.

In the actual implementation, we provide the platform-specific implementation for iOS and Android. In this case, we use the httpClient library to make the network request and parse the response.

Handling platform-specific dependencies

KMM allows you to handle platform-specific dependencies by using the expect and actual declarations. Here's an example of handling a platform-specific database dependency:

expect class Database {
    fun saveData(data: String)
}

actual class Database {
    actual fun saveData(data: String) {
        // Call the platform-specific database implementation
        iOSDatabase.saveData(data)
    }
}

In this example, we declare a Database class with a saveData function using the expect keyword. This declares the function signature in the shared code.

In the actual implementation, we provide the platform-specific implementation for iOS and Android. In this case, we call the saveData function of the iOSDatabase singleton.

Building and Deploying

Once you have developed your KMM app for iOS and Android, you can build and deploy it to the respective app stores. This section will cover the process of building the iOS and Android apps and publishing them to the App Store and Google Play.

Building the iOS and Android apps

To build the iOS app, follow these steps:

  1. Open the Xcode project for the iOS module of your KMM project.

  2. Select the target device and build configuration.

  3. Click the "Build" button to build the app.

To build the Android app, follow these steps:

  1. Open the Android module of your KMM project in Android Studio.

  2. Select the target device and build configuration.

  3. Click the "Build" button to build the app.

Publishing to the App Store and Google Play

To publish your KMM app to the App Store and Google Play, follow the respective guidelines and processes provided by Apple and Google. You will need to create developer accounts, prepare the app for release, and submit it for review.

Ensure that you follow the platform-specific guidelines and requirements for app submission, including providing appropriate app descriptions, icons, screenshots, and compliance with store policies.

Continuous integration and delivery

To automate the build and deployment process, you can set up continuous integration and delivery (CI/CD) pipelines using tools like Jenkins, Travis CI, or GitHub Actions. These tools allow you to automatically build, test, and deploy your KMM app whenever changes are pushed to the repository.

By setting up CI/CD pipelines, you can ensure that your app is continuously integrated, tested, and deployed, reducing the manual effort required for building and deploying the app.

Conclusion

In this tutorial, we explored Kotlin Multiplatform Mobile (KMM) and its capabilities for building mobile apps for iOS and Android. We covered the advantages of using KMM, the setup process, developing for iOS and Android, sharing code, and building and deploying the apps.

With KMM, developers can leverage the power of Kotlin and native platform-specific code to build high-performance and maintainable mobile apps. The ability to share code and business logic between iOS and Android significantly reduces development time and effort, while the seamless integration with platform-specific frameworks and APIs ensures a native-like user experience.

Kotlin Multiplatform Mobile is a powerful tool for software developers looking to streamline the mobile app development process and maximize code reuse. By adopting KMM, developers can build cross-platform apps that are efficient, performant, and maintainable.