Table of Contents
- Prerequisites
- Setting Up the Development Environment
- Creating Your First KMM Project
- Understanding the KMM Project Structure
- Writing Shared Business Logic
- Integrating Shared Logic with Android
- Integrating Shared Logic with iOS
- Testing the App
- Troubleshooting Common Issues
- Advanced KMM Concepts (Brief Overview)
- Conclusion
- References
Prerequisites
Before diving in, ensure you have the following tools installed:
- Android Studio (2022.2.1 or later): For Android development and KMM project management.
- Xcode (14.0 or later): Required for iOS development (only available on macOS).
- JDK 17: KMM requires Java Development Kit 17.
- macOS: To build and run iOS apps (KMM iOS development is only supported on macOS).
Setting Up the Development Environment
Step 1: Install Android Studio
Download Android Studio from the official website. During installation, select the “Android SDK,” “Android SDK Platform,” and “Android Virtual Device” components.
Step 2: Install the KMM Plugin
Open Android Studio, go to Preferences > Plugins, search for “Kotlin Multiplatform Mobile,” and install the plugin. Restart Android Studio to activate it.
Step 3: Configure Xcode
If you’re on macOS, install Xcode from the Mac App Store. After installation, open Xcode and accept the license agreement. Then, install the Xcode command-line tools:
xcode-select --install
Step 4: Verify JDK Installation
Check if JDK 17 is installed:
java -version
If not, download it from Adoptium and set it as the default JDK in Android Studio (File > Project Structure > SDK Location > JDK Location).
Creating Your First KMM Project
Step 1: Start a New KMM Project
Open Android Studio and click New Project. Select the Kotlin Multiplatform App template, then click Next.
Step 2: Configure Project Details
- Name: Enter a name (e.g., “KmmFirstApp”).
- Location: Choose a project directory.
- Language: Select “Kotlin” (default).
- Minimum SDK: For Android, choose API 24 (Android 7.0) or higher.
- iOS Framework Distribution: Select “Regular framework” (default for most cases).
Click Finish to generate the project.
Understanding the KMM Project Structure
A KMM project has three main modules:
1. shared Module
This is the core of your KMM app, containing code shared between Android and iOS. It has three source sets:
commonMain: Code shared across all platforms (e.g., data models, business logic).androidMain: Android-specific code (e.g., Android SDK integrations).iosMain: iOS-specific code (e.g., iOS SDK integrations).
2. androidApp Module
Android-specific app code (UI, activities, Jetpack Compose/SwiftUI). It depends on the shared module.
3. iosApp Module
iOS-specific app code (UI, ViewControllers, SwiftUI). It uses the shared module as a framework.
Writing Shared Business Logic
Let’s add a simple shared feature: a Greeting class that returns a personalized message.
Step 1: Add Code to commonMain
In the shared module, navigate to src/commonMain/kotlin/com/example/kmmfirstapp. Create a new Kotlin file Greeting.kt:
package com.example.kmmfirstapp
class Greeting {
private val platform = getPlatform()
fun greeting(): String {
return "Hello, ${platform.name}!"
}
}
// Expect declaration: Defines a common interface
expect class Platform {
val name: String
}
The expect keyword declares a type/function that must be implemented for each platform (Android and iOS).
Step 2: Implement Platform for Android
In src/androidMain/kotlin/com/example/kmmfirstapp, create Platform.kt:
package com.example.kmmfirstapp
// Actual implementation for Android
actual class Platform actual constructor() {
actual val name: String = "Android"
}
Step 3: Implement Platform for iOS
In src/iosMain/kotlin/com/example/kmmfirstapp, create Platform.kt:
package com.example.kmmfirstapp
// Actual implementation for iOS
actual class Platform actual constructor() {
actual val name: String = "iOS"
}
The actual keyword provides platform-specific implementations for expect declarations.
Integrating Shared Logic with Android
Now, let’s use the Greeting class in the Android app.
Step 1: Update Android UI
The androidApp module uses Jetpack Compose by default. Open androidApp/src/main/java/com/example/kmmfirstapp/MainActivity.kt:
package com.example.kmmfirstapp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val greeting = Greeting() // Shared class
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
GreetingText(greeting.greeting())
}
}
}
}
}
@Composable
fun GreetingText(message: String) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = message)
}
}
@Preview
@Composable
fun DefaultPreview() {
MyApplicationTheme {
GreetingText("Hello, Android!")
}
}
Here, we initialize Greeting from the shared module and display its greeting() result in the UI.
Integrating Shared Logic with iOS
Now, let’s use the Greeting class in the iOS app.
Step 1: Open the iOS Project
In Android Studio, right-click the iosApp module and select Open in Xcode. This opens the iOS project in Xcode.
Step 2: Update SwiftUI Code
The default iOS app uses SwiftUI. Open iosApp/iosApp/ContentView.swift:
import SwiftUI
// Import the shared KMM framework
import shared
struct ContentView: View {
let greeting = Greeting() // Shared Kotlin class
var body: some View {
VStack(spacing: 16) {
Text(greeting.greeting()) // Call shared function
.font(.title)
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Kotlin classes/functions in the shared module are exposed to Swift as regular Swift types. Here, Greeting and greeting() are called directly.
Testing the App
Run the Android App
- In Android Studio, select the
androidAppmodule from the run configurations dropdown. - Choose an Android emulator or physical device.
- Click Run (▶️). The app will launch, displaying “Hello, Android!“.
Run the iOS App
- In Xcode, select a simulator (e.g., “iPhone 14”) from the run configurations dropdown.
- Click Run (▶️). The app will launch, displaying “Hello, iOS!“.
Troubleshooting Common Issues
1. “Kotlin/Native Compilation Failed”
- Ensure Xcode is installed and up-to-date.
- Clean the project: Build > Clean Project (Android Studio) or
./gradlew clean(terminal).
2. “Shared Framework Not Found” in Xcode
- Rebuild the
sharedmodule: In Android Studio, run:shared:build. - In Xcode, go to Product > Clean Build Folder.
3. Expect/Actual Mismatch
- Ensure all
expectdeclarations have correspondingactualimplementations inandroidMainandiosMain.
Advanced KMM Concepts (Brief Overview)
Once you’re comfortable with the basics, explore these advanced topics:
- Networking: Use Ktor for cross-platform HTTP requests.
- Local Storage: Use SQLDelight for shared database logic.
- State Management: Use Jetpack Compose (Android) and SwiftUI (iOS) with shared state holders (e.g.,
ViewModel-like classes incommonMain).
Conclusion
You’ve built your first KMM app! You now understand how to share business logic between Android and iOS, integrate shared code into native UIs, and test across platforms. KMM reduces duplication and streamlines development while retaining native performance and UX.