KMP’nin ne olduğunu ve neden önemli olduğunu daha önce ele almıştık. Şimdi kolları sıvama vakti: gerçek bir proje oluşturun, içindeki her dosyayı anlayın, paylaşılan kod yazın ve hem Android hem iOS’ta çalıştırın.

Bu uzun bir rehber. Acele etmeyin. Sonunda çalışan bir çapraz platform (cross-platform) uygulamanız olacak ve her parçanın nasıl bir araya geldiğini tam olarak anlayacaksınız.

Bölüm 1: Ortamınızı Kurmak

Neye İhtiyacınız Var

AraçGerekli miAmacı
Android StudioEvetKMP geliştirme için IDE (en son kararlı sürüm)
XcodeEvet (sadece Mac)iOS uygulamalarını derler ve çalıştırır
JDK 17+EvetKotlin derleyicisi buna bağımlı
Mac bilgisayariOS içinApple, yalnızca macOS’ta çalışan Xcode’u zorunlu kılıyor
CocoaPodsİsteğe bağlıBazı KMP kütüphaneleri iOS için buna ihtiyaç duyar

Windows veya Linux kullanıyorsanız, yine de paylaşılan kod yazabilir ve Android uygulamasını derleyebilirsiniz. Ancak iOS’u derleyemez ya da çalıştıramazsınız. Bunun bir yolu yok, Apple, iOS derlemelerini kontrol ediyor.

Adım 1: Android Studio’yu Kurun

En son kararlı sürümü developer.android.com/studio adresinden indirin. Kurun ve şunlara sahip olduğunuzdan emin olun:

  • Android SDK (API 34 veya üzeri)
  • Bir Android emülatörü (veya fiziksel cihaz)

Adım 2: Kotlin Multiplatform Eklentisini Kurun

Bu, çoğu rehberin atladığı adım, sonra da neden iOS çalıştırma yapılandırmalarını görmediğinize şaşırırsınız.

  1. Android Studio’yu açın
  2. Settings → Plugins → Marketplace yolunu izleyin
  3. “Kotlin Multiplatform” araması yapın
  4. Kurun ve Android Studio’yu yeniden başlatın

Bu eklenti olmadan, Android Studio, KMP projelerini nasıl ele alacağını bilmez.

Adım 3: Xcode’u Kurun (Sadece Mac)

Xcode’u Mac App Store’dan indirin. Kurduktan sonra:

# Komut satırı araçlarını kur
sudo xcode-select --install

# Lisansı kabul et
sudo xcodebuild -license accept

Xcode’u en az bir kez açın, böylece ek bileşenleri kurar.

Adım 4: kdoctor ile Her Şeyi Doğrulayın

kdoctor, tüm KMP ortamınızı tek seferde kontrol eden bir komut satırı aracı:

# kdoctor'ı kur
brew install kdoctor

# Kontrolü çalıştır
kdoctor

Şunları kontrol eder:

  • Java sürümü
  • Android Studio ve SDK
  • Xcode ve komut satırı araçları
  • CocoaPods (kuruluysa)
  • Kotlin eklenti sürümü

Devam etmeden önce bildirdiği sorunları çözün. Yeşil onay işaretleri hazır olduğunuz anlamına gelir.

Homebrew’unuz yoksa manuel kontrol edin:

java -version           # 17+ gerekli
xcode-select --version  # Xcode CLT kurulu mu

Bölüm 2: Projeyi Oluşturmak

KMP Wizard’ı Kullanmak (Önerilen)

kmp.jetbrains.com adresindeki KMP Wizard, bir proje oluşturmanın en kolay yolu. Gradle yapılandırma başağrısı yok.

Adım 1: kmp.jetbrains.com adresine gidin

Adım 2: Proje detaylarını doldurun:

  • Project name: MyKmpApp (ya da istediğiniz herhangi bir şey)
  • Project ID: com.ornek.mykmpapp

Adım 3: Platformlarınızı seçin:

  • Android‘i işaretleyin
  • iOS‘u işaretleyin
  • İsteğe bağlı olarak Desktop veya Web‘i işaretleyin

Adım 4: UI paylaşımını seçin:

  • “Share UI with Compose Multiplatform”: tüm platformlar için tek bir Compose UI. Öğrenmek ve prototip oluşturmak için iyi.
  • “Do not share UI”: her platformda native UI (Android’de Compose, iOS’ta SwiftUI). Platforma özgü görünüm ve his gerektiren üretim uygulamaları için daha iyi.

Bu rehber için “Share UI with Compose Multiplatform” seçeneğini seçin, böylece ayrı bir Swift kodu yazmadan paylaşılan koda odaklanabiliriz.

Adım 5: Download butonuna tıklayın, dosyayı açın ve klasörü Android Studio’da açın.

Android Studio’yu Kullanmak

Alternatif olarak, Android Studio sürümünüz destekliyorsa:

  1. File → New → New Project
  2. Şablon listesinden Kotlin Multiplatform‘u seçin
  3. Proje adınızı ve paketinizi ayarlayın
  4. Platformları seçin (Android + iOS)
  5. Finish’e tıklayın

İlk Gradle Senkronizasyonu

Proje açıldıktan sonra, Android Studio Gradle senkronizasyonuna başlar. Bu, tüm bağımlılıkları indirir.

İlk senkronizasyon 5-10 dakika sürer. Bu normaldir. KMP projeleri, Kotlin/Native derleyicisini, iOS framework üretecilerini ve çok platformlu kütüphaneleri içerdiği için normal Android projelerinden daha fazla bağımlılığa sahiptir.

Senkronizasyon başarısız olursa şunları kontrol edin:

  • İnternet bağlantısı
  • Proxy ayarları
  • JDK sürümü (17+ gerekli)

Bölüm 3: Proje Yapısını Anlamak

Proje açıldıktan sonra şuna benzer bir yapı görürsünüz:

MyKmpApp/
├── shared/                         ← PAYLAŞILAN MODÜL
│   ├── build.gradle.kts            ← Hedefleri ve bağımlılıkları yapılandırır
│   └── src/
│       ├── commonMain/             ← HER YERDE çalışan kod
│       │   └── kotlin/
│       │       ├── Platform.kt     ← expect bildirimi
│       │       └── Greeting.kt    ← paylaşılan iş mantığı
│       ├── commonTest/             ← Paylaşılan kod için testler
│       │   └── kotlin/
│       ├── androidMain/            ← Android'e özgü kod
│       │   └── kotlin/
│       │       └── Platform.android.kt  ← Android için actual
│       └── iosMain/                ← iOS'a özgü kod
│           └── kotlin/
│               └── Platform.ios.kt      ← iOS için actual
├── composeApp/                     ← UYGULAMA MODÜLÜ
│   ├── build.gradle.kts
│   └── src/
│       ├── commonMain/             ← Paylaşılan Compose UI
│       │   └── kotlin/
│       │       └── App.kt         ← Ana uygulama composable'ı
│       ├── androidMain/            ← Android giriş noktası
│       │   └── kotlin/
│       │       └── MainActivity.kt
│       │   └── AndroidManifest.xml
│       └── iosMain/                ← iOS giriş noktası
├── iosApp/                         ← iOS XCODE PROJESİ
│   └── iosApp/
│       ├── ContentView.swift       ← SwiftUI sarmalayıcı
│       └── iOSApp.swift            ← iOS uygulama giriş noktası
├── build.gradle.kts                ← Kök derleme yapılandırması
├── settings.gradle.kts             ← Modül bildirimleri
├── gradle.properties               ← Proje özellikleri
└── gradle/
    └── libs.versions.toml          ← Bağımlılık sürümleri

Bu çok fazla klasör. Her birini açıklayalım.

shared/: KMP Projenizin Kalbi

Paylaşılan Kotlin kodunuzun yaşadığı yer burası. commonMain içindeki her şey her platformda çalışır. androidMain içindeki her şey sadece Android’de çalışır. iosMain içindeki her şey sadece iOS’ta çalışır.

Kural basit:

  • Kodunuz herhangi bir platformda çalışabilir mi? → commonMain‘e koyun
  • Android API’larına mı ihtiyaç duyuyor? → androidMain‘e koyun
  • Apple API’larına mı ihtiyaç duyuyor? → iosMain‘e koyun

composeApp/: Paylaşılan Kodu Kullanan Uygulama

“Share UI with Compose Multiplatform” seçtiyseniz, bu modül tüm platformlarda çalışan Compose UI’ı içerir. Kendi commonMain‘i (paylaşılan UI), androidMain‘i (Android giriş noktası) ve iosMain‘i (iOS giriş noktası) vardır.

“Do not share UI” seçtiyseniz, bunun yerine sadece Android uygulamasını içeren androidApp/ olurdu.

iosApp/: Xcode Projesi

Bu, iOS uygulama projesi. Compose Multiplatform ile bile, iOS için giriş noktası olarak bir Xcode projesine ihtiyacınız var. ContentView.swift dosyası, Compose UI’ınızı iOS için sarmalıyor.

Bölüm 4: Varsayılan Kodu Anlamak

expect/actual Deseni

shared/src/commonMain/kotlin/Platform.kt dosyasını açın:

// commonMain: NEYE ihtiyacımız olduğunu bildirir
// "expect" şu anlama gelir: her platform kendi uygulamasını sağlamalı
expect fun getPlatformName(): String

Bu şunu söylüyor: “Bir String döndüren getPlatformName adında bir fonksiyona ihtiyacım var. Her platform ne döndüreceğine kendi karar verir.”

shared/src/androidMain/kotlin/Platform.android.kt dosyasını açın:

// androidMain: Android yanıtını sağlar
actual fun getPlatformName(): String = "Android ${android.os.Build.VERSION.SDK_INT}"

shared/src/iosMain/kotlin/Platform.ios.kt dosyasını açın:

// iosMain: iOS yanıtını sağlar
import platform.UIKit.UIDevice

actual fun getPlatformName(): String = UIDevice.currentDevice.systemName() +
    " " + UIDevice.currentDevice.systemVersion

Dikkat edin:

  • commonMain’de expect → “Buna ihtiyacım var”
  • androidMain’de actual → “İşte Android sürümü”
  • iosMain’de actual → “İşte iOS sürümü”

Derleyici, her expect bildiriminin her platformda karşılık gelen bir actual‘a sahip olduğundan emin olur. Birini unutursanız, proje derlenmez. Eksik uygulamalardan kaynaklanan çalışma zamanı çökmesi yok.

Greeting Sınıfı

shared/src/commonMain/kotlin/Greeting.kt dosyasını açın:

class Greeting {
    fun greet(): String {
        return "Hello from ${getPlatformName()}!"
    }
}

Bu paylaşılan koddur. Her platformda farklı değerler döndüren getPlatformName()‘i çağırır:

  • Android’de: “Hello from Android 35!”
  • iOS’ta: “Hello from iOS 18.2!”

Aynı kod, farklı davranış. KMP’nin gücü bu.

Bölüm 5: Uygulamayı Çalıştırmak

Android’de Çalıştırma

  1. Android Studio’da, araç çubuğu açılır menüsünden composeApp çalıştırma yapılandırmasını seçin
  2. Bir Android emülatörü veya bağlı cihaz seçin
  3. Run düğmesine (yeşil üçgen) tıklayın

Ya da terminalden:

./gradlew :composeApp:assembleDebug
./gradlew :composeApp:installDebug

Karşılama mesajını gösteren bir ekran görmelisiniz.

iOS’ta Çalıştırma

Android Studio’dan (KMP eklentisiyle):

  1. Açılır menüden iosApp çalıştırma yapılandırmasını seçin
  2. Bir iOS simülatörü seçin (örneğin iPhone 16)
  3. Run’a tıklayın

İlk iOS derlemesi, Kotlin/Native framework’ünü derlemesi gerektiği için Android’den daha uzun sürer. Sonraki derlemeler daha hızlıdır.

Xcode’dan:

  1. iosApp/iosApp.xcodeproj dosyasını Xcode’da açın
  2. Cihaz açılır menüsünden bir simülatör seçin
  3. Run düğmesine (veya Cmd+R) tıklayın

Yaygın iOS derleme sorunu: “framework not found Shared” hatası alırsanız şunu çalıştırın:

./gradlew :shared:linkDebugFrameworkIosSimulatorArm64

Bu, iOS’un ihtiyaç duyduğu paylaşılan framework’ü derler.

Desktop’ta Çalıştırma (Wizard’da Seçildiyse)

./gradlew :composeApp:run

Aynı Compose UI ile bir masaüstü penceresi açılır. Aynı kod, üçüncü platform.

Bölüm 6: İlk Gerçek Paylaşılan Kodunuzu Yazmak

Karşılama mesajının ötesine geçip faydalı bir şey yazalım.

Paylaşılan Veri Modelleri

shared/src/commonMain/kotlin/models/User.kt dosyasını oluşturun:

package com.ornek.mykmpapp.models

// Bu data class Android, iOS, Desktop ve Web'de çalışır
// Bir kez tanımla, her yerde kullan

data class User(
    val id: String,
    val name: String,
    val email: String,
    val joinedYear: Int = 2026
) {
    // Doğrulama mantığı: tüm platformlarda paylaşılır
    fun isValid(): Boolean {
        return name.isNotBlank() &&
            email.contains("@") &&
            email.contains(".")
    }

    // Biçimlendirme mantığı: her platformda aynı
    fun displayName(): String {
        return if (name.isNotBlank()) name
        else email.substringBefore("@")
    }

    // İş mantığı: her yerde tutarlı
    fun membershipYears(): Int {
        return 2026 - joinedYear
    }
}

Bu User sınıfı, Android ve iOS’ta aynı şekilde çalışır. Doğrulama kuralları, biçimlendirme, iş mantığı, hepsi bir kez yazıldı. isValid() içindeki bir hatayı düzeltirseniz, her iki platformda da aynı anda düzelir.

Paylaşılan Yardımcı Fonksiyonlar

shared/src/commonMain/kotlin/utils/StringUtils.kt dosyasını oluşturun:

package com.ornek.mykmpapp.utils

// Tüm platformlarda kullanılabilir yardımcı fonksiyonlar

object StringUtils {

    fun capitalizeWords(text: String): String {
        return text.split(" ")
            .joinToString(" ") { word ->
                word.replaceFirstChar { it.uppercase() }
            }
    }

    fun truncate(text: String, maxLength: Int, suffix: String = "..."): String {
        return if (text.length <= maxLength) text
        else text.take(maxLength - suffix.length) + suffix
    }

    fun isValidEmail(email: String): Boolean {
        return email.contains("@") &&
            email.contains(".") &&
            email.indexOf("@") < email.lastIndexOf(".")
    }

    fun slugify(text: String): String {
        return text.lowercase()
            .replace(Regex("[^a-z0-9\\s-]"), "")
            .replace(Regex("\\s+"), "-")
            .trim('-')
    }
}

Paylaşılan İş Mantığı

shared/src/commonMain/kotlin/repository/UserRepository.kt dosyasını oluşturun:

package com.ornek.mykmpapp.repository

import com.ornek.mykmpapp.models.User

// Repository deseni: paylaşılan veri erişim mantığı
// Gerçek bir uygulamada bu bir API veya veritabanı çağırırdı
// Şimdilik bellek içi veri kullanıyoruz

class UserRepository {

    private val users = mutableListOf(
        User("1", "Alex", "alex@example.com", 2023),
        User("2", "Sam", "sam@example.com", 2024),
        User("3", "Jordan", "jordan@example.com", 2025),
        User("4", "Taylor", "taylor@example.com", 2026),
    )

    fun getAllUsers(): List<User> = users.toList()

    fun getUserById(id: String): User? = users.find { it.id == id }

    fun searchUsers(query: String): List<User> {
        val lowerQuery = query.lowercase()
        return users.filter {
            it.name.lowercase().contains(lowerQuery) ||
                it.email.lowercase().contains(lowerQuery)
        }
    }

    fun addUser(user: User): Boolean {
        if (!user.isValid()) return false
        if (users.any { it.email == user.email }) return false
        users.add(user)
        return true
    }

    fun deleteUser(id: String): Boolean {
        return users.removeAll { it.id == id }
    }

    fun getUserCount(): Int = users.size
}

Bu repository’nin tamamı (veri modelleri, doğrulama, arama, CRUD işlemleri) paylaşılan koddur. Platformlar arasında sıfır tekrar.

Paylaşılan Kodu Uygulamada Kullanmak

Şimdi bu paylaşılan kodu Compose UI’da kullanalım. composeApp/src/commonMain/kotlin/App.kt dosyasını açın veya oluşturun:

@Composable
fun App() {
    val repository = remember { UserRepository() }
    var users by remember { mutableStateOf(repository.getAllUsers()) }
    var searchQuery by remember { mutableStateOf("") }

    MaterialTheme {
        Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
            Text(
                "Users (${repository.getUserCount()})",
                style = MaterialTheme.typography.headlineMedium
            )

            // Arama çubuğu
            OutlinedTextField(
                value = searchQuery,
                onValueChange = {
                    searchQuery = it
                    users = if (it.isEmpty()) repository.getAllUsers()
                    else repository.searchUsers(it)
                },
                label = { Text("Search") },
                modifier = Modifier.fillMaxWidth()
            )

            Spacer(modifier = Modifier.height(16.dp))

            // Kullanıcı listesi
            LazyColumn {
                items(users) { user ->
                    Column(modifier = Modifier.padding(vertical = 8.dp)) {
                        Text(user.displayName(), fontWeight = FontWeight.Bold)
                        Text(user.email, fontSize = 14.sp)
                        Text(
                            "Member for ${user.membershipYears()} year(s)",
                            fontSize = 12.sp,
                            color = Color.Gray
                        )
                    }
                }
            }
        }
    }
}

Bu Compose kodu DA paylaşılır, Android, iOS ve Desktop’ta çalışır. UserRepository, User data class’ı, displayName(), membershipYears(): hepsi paylaşılan modülden geliyor.

Bölüm 7: Gradle Yapılandırmasını Anlamak

settings.gradle.kts

// Projede hangi modüllerin var olduğunu bildirir
rootProject.name = "MyKmpApp"
include(":shared")        // Paylaşılan Kotlin modülü
include(":composeApp")    // Uygulama modülü (Android/iOS/Desktop)

shared/build.gradle.kts

Bu, en önemli derleme dosyası. Hangi platformların hedefleneceğini yapılandırır:

kotlin {
    // Android hedefi
    androidTarget {
        compilations.all {
            kotlinOptions {
                jvmTarget = "17"
            }
        }
    }

    // iOS hedefleri: tam uyumluluk için üçü de gerekli
    listOf(
        iosX64(),              // Intel Mac simülatörleri
        iosArm64(),            // Gerçek iOS cihazları
        iosSimulatorArm64()    // Apple Silicon Mac simülatörleri
    ).forEach {
        it.binaries.framework {
            baseName = "Shared"   // iOS framework'ünün adı
            isStatic = true
        }
    }

    // Kaynak setleri: bağımlılıkların gittiği yer
    sourceSets {
        commonMain.dependencies {
            // TÜM platformlar için bağımlılıklar
            // örneğin kotlinx-coroutines, kotlinx-serialization
        }

        androidMain.dependencies {
            // Sadece Android bağımlılıkları
        }

        iosMain.dependencies {
            // Sadece iOS bağımlılıkları
        }

        commonTest.dependencies {
            // Paylaşılan kod için test bağımlılıkları
            implementation(kotlin("test"))
        }
    }
}

Anahtar kavramlar:

  • androidTarget(): Android derlemesini etkinleştirir
  • iosX64(), iosArm64(), iosSimulatorArm64(): tam cihaz/simülatör kapsaması için üç iOS hedefi
  • sourceSets: her platform için bağımlılık bildirdiğiniz yer
  • commonMain‘deki bağımlılıklar otomatik olarak tüm platformlara yayılır

gradle.properties

# Gradle daemon için bellek
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8

# Kotlin kod stili
kotlin.code.style=official

# Compose Multiplatform'u etkinleştir
kotlin.mpp.applyDefaultHierarchyTemplate=true

Bölüm 8: iOS Kotlin Kodunuzu Nasıl Görür

iOS için derlediğinizde, KMP, paylaşılan Kotlin kodunuzu Shared.framework adında native bir Objective-C framework’üne derler. Swift bu framework’ü doğrudan import edebilir.

Kotlin, Swift’te Neye Dönüşür

KotlinSwift
data class User(...)class User
object CalculatorCalculator.shared (singleton)
fun greet(): Stringfunc greet() -> String
suspend fun getUsers()Asenkron callback (veya sarmalayıcıyla async)
sealed interfaceProtocol + sınıflar
enum classKotlinEnum
List<User>[User] (NSArray)

Örnek: Swift’te bir Kotlin object’i:

// Kotlin (shared/commonMain)
object Calculator {
    fun add(a: Double, b: Double): Double = a + b
}
// Swift (iosApp)
import Shared

let result = Calculator.shared.add(a: 10.0, b: 5.0)
print(result) // 15.0

.shared, Kotlin object singleton’larının Swift’te nasıl göründüğü. Alışmak birkaç dakika alır, ama sorunsuz çalışır.

Bölüm 9: Test Yazmak ve Çalıştırmak

Paylaşılan kod, paylaşılan testlere sahip olabilir. shared/src/commonTest/kotlin/UserTest.kt dosyasını oluşturun:

package com.ornek.mykmpapp

import com.ornek.mykmpapp.models.User
import com.ornek.mykmpapp.utils.StringUtils
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class UserTest {

    @Test
    fun validUserShouldReturnTrue() {
        val user = User("1", "Alex", "alex@example.com")
        assertTrue(user.isValid())
    }

    @Test
    fun invalidEmailShouldReturnFalse() {
        val user = User("1", "Alex", "not-an-email")
        assertFalse(user.isValid())
    }

    @Test
    fun emptyNameShouldReturnFalse() {
        val user = User("1", "", "alex@example.com")
        assertFalse(user.isValid())
    }

    @Test
    fun displayNameShouldUseEmailWhenNameIsBlank() {
        val user = User("1", "", "alex@example.com")
        assertEquals("alex", user.displayName())
    }

    @Test
    fun membershipYearsShouldCalculateCorrectly() {
        val user = User("1", "Alex", "alex@example.com", 2024)
        assertEquals(2, user.membershipYears())
    }
}

class StringUtilsTest {

    @Test
    fun capitalizeWordsShouldWork() {
        assertEquals("Hello World", StringUtils.capitalizeWords("hello world"))
    }

    @Test
    fun truncateShouldAddSuffix() {
        assertEquals("Hello...", StringUtils.truncate("Hello World", 8))
    }

    @Test
    fun isValidEmailShouldWork() {
        assertTrue(StringUtils.isValidEmail("alex@example.com"))
        assertFalse(StringUtils.isValidEmail("not-email"))
        assertFalse(StringUtils.isValidEmail("@example.com"))
    }

    @Test
    fun slugifyShouldWork() {
        assertEquals("hello-world", StringUtils.slugify("Hello World!"))
    }
}

Testleri çalıştırın:

# Tüm platformlar için testleri çalıştır
./gradlew :shared:allTests

# Sadece Android için testleri çalıştır
./gradlew :shared:testDebugUnitTest

# Sadece iOS için testleri çalıştır
./gradlew :shared:iosSimulatorArm64Test

Bu testler hem Android’de hem iOS’ta çalışır, aynı test kodu, paylaşılan mantığın her platformda doğru çalıştığını doğrular.

Türkçe Dokümantasyon Eksikliği: Bu Sizi Nasıl Etkiler

KMP ile çalışırken karşılaşacağınız pratik bir gerçek şu: JetBrains’in resmi dokümantasyonu, topluluk forumları (Kotlin Slack, Stack Overflow) ve neredeyse tüm hata mesajı çözümleri İngilizce. Türkçe kaynaklı KMP eğitim içeriği hâlâ çok az, bu yazı gibi rehberler dışında Android geliştiricilerin çoğu doğrudan resmi İngilizce dokümantasyona veya İngilizce YouTube içeriğine yönelmek zorunda kalıyor. Bunun pratik bir sonucu var: kdoctor gibi bir araç bir hata verdiğinde ya da Gradle senkronizasyonu tuhaf bir mesajla başarısız olduğunda, hata mesajını doğrudan İngilizce olarak arama motoruna yapıştırmak, Türkçe bir karşılığını aramaktan çok daha hızlı sonuç veriyor. Ekibinizde İngilizce teknik dokümantasyon okumakta zorlanan geliştiriciler varsa, KMP’ye geçiş kararı verirken bunu bir öğrenme eğrisi maliyeti olarak hesaba katmakta fayda var, çünkü resmi kaynakların Türkçe çevirisi kısa vadede gelmeyecek gibi görünüyor.

Sık Yapılan Hatalar

Hata 1: KMP Eklentisini Unutmak

Android Studio’ya Kotlin Multiplatform eklentisini kurmazsanız şunları göremezsiniz:

  • iOS çalıştırma yapılandırmaları
  • KMP proje şablonları
  • Kaynak setleri arasında düzgün kod gezinimi

Çözüm: Settings → Plugins → “Kotlin Multiplatform” ara → Kur.

Hata 2: commonMain’de Android API’larını Kullanmak

// KÖTÜ: bu iOS'ta çöker çünkü Android API'ları orada yok
// shared/src/commonMain/kotlin/
import android.util.Log  // Bu iOS için derlenmez!

fun logMessage(msg: String) {
    Log.d("TAG", msg)  // Sadece Android API'sı
}
// İYİ: platforma özgü API'lar için expect/actual kullan
// shared/src/commonMain/kotlin/
expect fun logMessage(msg: String)

// shared/src/androidMain/kotlin/
actual fun logMessage(msg: String) {
    android.util.Log.d("TAG", msg)
}

// shared/src/iosMain/kotlin/
actual fun logMessage(msg: String) {
    platform.Foundation.NSLog(msg)
}

Hata 3: Kaynak Seti Görünürlüğünü Anlamamak

commonMain şunu görebilir: sadece commonMain
androidMain şunu görebilir: commonMain + androidMain
iosMain şunu görebilir: commonMain + iosMain

commonMain ŞUNU GÖREMEZ: androidMain veya iosMain

commonMain’de Android kodu kullanmaya çalışırsanız derlenmez. Aralarında köprü kurmak için expect/actual kullanın.

Hata 4: Büyük İlk Gradle Senkronizasyonu

İlk senkronizasyon yaklaşık 500 MB bağımlılık indirir (Kotlin/Native derleyicisi, iOS araç zincirleri vb.). Paniğe kapılmayın. İyi bir internet bağlantısı kullanın ve bekleyin.

Hata 5: iOS Framework’ünü Derlememek

Xcode paylaşılan kodunuzu bulamıyorsa:

# Framework'ü manuel derle
./gradlew :shared:linkDebugFrameworkIosSimulatorArm64

Bu, Xcode’un ihtiyaç duyduğu Shared.framework‘ü üretir.

Hızlı Referans

İşlemKomut
Android’i derle./gradlew :composeApp:assembleDebug
iOS framework’ünü derle./gradlew :shared:linkDebugFrameworkIosSimulatorArm64
Testleri çalıştır (tümü)./gradlew :shared:allTests
Testleri çalıştır (Android)./gradlew :shared:testDebugUnitTest
Desktop uygulamasını çalıştır./gradlew :composeApp:run
Temiz derleme./gradlew clean
Ortamı kontrol etkdoctor

İlgili Yazılar