لماذا Kotlin ليس فقط لنظام Android؟
\n\nإذا كنت لا تزال تعتقد أن Kotlin هو مجرد "Java محسّنة" لنظام Android، فأنت تفوت الأمر الأهم. في عالم يريد فيه الجميع كتابة كود واحد وتشغيله في كل مكان، يتحول Kotlin Multiplatform (KMP) إلى "قاتل" حقيقي لأطر العمل مثل Flutter وReact Native. ولكن على عكسهم، لا يجبرك Kotlin على التخلي عن واجهة المستخدم الأصلية أو تعلم JavaScript.
\n\nتخيل: أنت تكتب منطق الأعمال، وطلبات الشبكة، والعمل مع قاعدة البيانات مرة واحدة بلغة Kotlin. ثم تستخدم هذا الكود على Android وiOS والويب وحتى على الخادم (Ktor). هل يبدو هذا كخيال علمي؟ مرحبًا بك في واقع التطوير عبر المنصات باستخدام Kotlin.
\n\nفي هذه المقالة، لن نتحدث فقط عن النظرية. سنعرض أمثلة حقيقية على الكود، ونقارن KMP مع المنافسين، ونقدم لك خطة خطوة بخطوة للبدء اليوم.
\n\nما هو Kotlin Multiplatform (KMP) ولماذا هو مهم؟
\n\nKMP ليس إطار عمل. إنها تقنية ترجمة مدمجة في لغة Kotlin. تسمح بترجمة الكود المشترك (common code) إلى منصات مختلفة:
\n\n- \n
- Android — كود بايت JVM (كالمعتاد). \n
- iOS — ملف ثنائي أصلي (عبر LLVM). \n
- JavaScript/Web — كود JS للمتصفح. \n
- Native (Linux, Windows, macOS) — عبر Kotlin/Native. \n
الميزة الرئيسية: تكتب expect/actual — تعلن عن واجهة برمجة التطبيقات المتوقعة في الكود المشترك، وتنفذها لكل منصة على حدة. كل شيء آخر مشترك.
\n\nمثال 1: وحدة مشتركة لطلبات الشبكة
\n\nلنكتب عميل HTTP بسيط يعمل على Android وiOS. سنستخدم Ktor — عميل مكتوب بلغة Kotlin.
\n\nالخطوة 1: هيكل المشروع (Gradle)
\n\nفي ملف build.gradle.kts للوحدة المشتركة:
plugins {\n kotlin("multiplatform")\n id("io.ktor.plugin") version "2.3.7"\n}\n\nkotlin {\n androidTarget()\n iosX64()\n iosArm64()\n iosSimulatorArm64()\n\n sourceSets {\n val commonMain by getting {\n dependencies {\n implementation("io.ktor:ktor-client-core:2.3.7")\n implementation("io.ktor:ktor-client-content-negotiation:2.3.7")\n implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.7")\n }\n }\n val androidMain by getting {\n dependencies {\n implementation("io.ktor:ktor-client-android:2.3.7")\n }\n }\n val iosMain by creating {\n dependsOn(commonMain)\n dependencies {\n implementation("io.ktor:ktor-client-darwin:2.3.7")\n }\n }\n }\n}\n\nالخطوة 2: الكود المشترك (commonMain)
\n\nلننشئ data class وعميل API:
\n\n// commonMain/kotlin/com/example/User.kt\nimport kotlinx.serialization.Serializable\n\n@Serializable\ndata class User(\n val id: Int,\n val name: String,\n val email: String\n)\n\n// commonMain/kotlin/com/example/ApiClient.kt\nimport io.ktor.client.*\nimport io.ktor.client.call.*\nimport io.ktor.client.plugins.contentnegotiation.*\nimport io.ktor.client.request.*\nimport io.ktor.serialization.kotlinx.json.*\n\nclass ApiClient {\n private val client = HttpClient {\n install(ContentNegotiation) {\n json()\n }\n }\n\n suspend fun fetchUser(id: Int): User {\n return client.get("https://jsonplaceholder.typicode.com/users/$id").body()\n }\n}\n\nهل ترى؟ لا توجد جمل if، ولا فحوصات منصة. مجرد Kotlin نقي.
\n\nمثال 2: Expect/Actual للعمل مع SharedPreferences
\n\nلنفترض أننا بحاجة لحفظ رمز مميز (token). على Android — SharedPreferences، على iOS — UserDefaults. نعرض سحر KMP:
\n\nالكود المشترك (commonMain):
\n\n// commonMai