Skip to main content

Getting Started with Kotlin Multiplatform

· 3 min read
BrewKits Team
Mobile Development Enthusiasts

Kotlin Multiplatform (KMP) is revolutionizing cross-platform development. Let's explore why and how to get started!

What is Kotlin Multiplatform?

Kotlin Multiplatform allows you to write code once and share it across multiple platforms:

  • Android (native performance)
  • iOS (native performance)
  • Web (JavaScript/Wasm)
  • Desktop (JVM, Windows, macOS, Linux)
  • Server (JVM, Node.js)

Unlike other cross-platform solutions, KMP lets you share what makes sense while keeping platform-specific code where needed.

Why Choose KMP?

True Native Performance

KMP compiles to native code for each platform - no bridge, no virtual machine overhead.

Gradual Adoption

Start by sharing a small piece of code and gradually increase sharing as you get comfortable.

Type Safety

Kotlin's strong type system catches errors at compile time, not runtime.

Modern Language Features

  • Null safety
  • Coroutines for async programming
  • Extension functions
  • Data classes
  • And much more!

Setting Up Your First KMP Project

Prerequisites

Install:

  • JDK 17+
  • Android Studio or IntelliJ IDEA
  • Xcode (for iOS development on macOS)
  • Kotlin 1.9.0+

Create a New Project

# Using IntelliJ IDEA
File → New → Project → Kotlin Multiplatform Library

Your First Shared Code

Common Code (Shared Logic)

// commonMain/kotlin/Greeting.kt
class Greeting {
fun greet(): String {
return "Hello from ${getPlatform().name}!"
}
}

expect fun getPlatform(): Platform

interface Platform {
val name: String
}

Platform-Specific Implementations

Android:

// androidMain/kotlin/Platform.android.kt
actual fun getPlatform(): Platform = AndroidPlatform()

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

iOS:

// iosMain/kotlin/Platform.ios.kt
actual fun getPlatform(): Platform = IOSPlatform()

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

Testing Your Shared Code

// commonTest/kotlin/GreetingTest.kt
class GreetingTest {
@Test
fun testGreeting() {
val greeting = Greeting().greet()
assertTrue(greeting.contains("Hello"))
}
}

Run tests:

./gradlew allTests

Real-World Use Cases

1. Networking & API Clients

Share HTTP client logic using Ktor:

class ApiClient {
private val client = HttpClient {
install(ContentNegotiation) {
json()
}
}

suspend fun fetchUsers(): List<User> {
return client.get("https://api.example.com/users").body()
}
}

2. Business Logic

class UserValidator {
fun validateEmail(email: String): Boolean {
return email.contains("@") && email.length > 5
}

fun validatePassword(password: String): Boolean {
return password.length >= 8
}
}

3. Data Models

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

4. Database Layer

Using SQLDelight:

class UserRepository(private val database: Database) {
fun getUser(id: String): User? {
return database.userQueries.selectById(id).executeAsOneOrNull()
}

fun saveUser(user: User) {
database.userQueries.insert(user.id, user.name, user.email)
}
}

Common Patterns

State Management with StateFlow

class UserViewModel {
private val _users = MutableStateFlow<List<User>>(emptyList())
val users: StateFlow<List<User>> = _users.asStateFlow()

fun loadUsers() {
viewModelScope.launch {
_users.value = repository.fetchUsers()
}
}
}

Dependency Injection with Koin

val appModule = module {
single { ApiClient() }
single { UserRepository(get()) }
factory { UserViewModel(get()) }
}

fun initKoin() {
startKoin {
modules(appModule)
}
}

What to Share vs. What to Keep Native

✅ Great Candidates for Sharing

  • Business logic
  • Data models
  • Networking code
  • Data persistence
  • Validation logic
  • Utilities and helpers

❌ Keep Platform-Specific

  • UI (use native frameworks)
  • Platform-specific APIs (camera, location, etc.)
  • Platform-specific optimizations
  • Deep platform integrations

Next Steps

Ready to dive deeper? Check out:

Resources


Ready to build once and deploy everywhere? Join us on this journey!