← Назад к вопросам

Какие знаешь особенности common code в Kotlin Multiplatform?

2.8 Senior🔥 151 комментариев
#Kotlin основы#Архитектура и паттерны#Многомодульность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Особенности написания common code в Kotlin Multiplatform

Разработка common code (общего кода) в Kotlin Multiplatform (KMP) — это основа для создания кросс-платформенных приложений. Этот код размещается в shared модуле и предназначен для компиляции на все целевые платформы (Android, iOS, Desktop, Web). Его особенности напрямую связаны с философией KMP: максимальная переиспользуемость при сохранении гибкости для платформенных реализаций.

1. Ограничения и совместимость

Common код должен быть строго platform-independent. Это означает:

  • Отсутствие прямых зависимостей от платформенных SDK: нельзя напрямую использовать классы из Android SDK (android.view.View) или iOS Foundation (NSString).
  • Использование только Kotlin Standard Library и общих многоплатформенных библиотек: доступны kotlin.collections, kotlin.coroutines, kotlin.io (в базовом виде), а также библиотеки от JetBrains и community (kotlinx.serialization, kotlinx.coroutines, ktor для сетевых запросов в common части).

Пример недопустимого кода в common модуле:

// НЕВЕРНО - платформенный класс
import android.widget.Toast

fun showMessage(message: String) {
    Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}

Пример верного подхода:

// Объявляем ожидаемый declaration (expect) в common коде
expect fun showMessage(message: String)

// Затем реализуем (actual) в платформенных модулях
// Для Android:
actual fun showMessage(message: String) {
    Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}

// Для iOS:
actual fun showMessage(message: String) {
    // Используем iOS API через cinterop или другие механизмы
}

2. Механизм expect/actual

Это центральная концепция для работы с платформенными особенностями.

  • expect declaration: в common коде объявляется функция, класс, свойство или даже тип, который должен быть реализован на каждой платформе. Это контракт.
  • actual implementation: в каждом платформенном модуле (androidMain, iosMain) предоставляется реализация, использующая нативные API.

Пример с типом:

// В commonMain
expect class PlatformDateTime() {
    fun getCurrentTime(): String
}

// В androidMain
import java.text.SimpleDateFormat
import java.util.Date

actual class PlatformDateTime {
    actual fun getCurrentTime(): String {
        val formatter = SimpleDateFormat("HH:mm:ss")
        return formatter.format(Date())
    }
}

// В iosMain
import kotlinx.datetime.*

actual class PlatformDateTime {
    actual fun getCurrentTime(): String {
        // Используем библиотеку kotlinx.datetime, которая также multiplatform
        val current = Clock.System.now()
        return current.toString()
    }
}

3. Организация исходного кода и зависимости

  • Структура модуля: В shared модуле существуют директории commonMain, androidMain, iosMain, desktopMain и т.д. Common код живет только в commonMain.
  • Gradle зависимости в commonMain: В build.gradle.kts общего модуля зависимости для commonMain указываются в блоке sourceSets.
kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.0")
            implementation("io.ktor:ktor-client-core:2.3.0")
        }
        androidMain.dependencies {
            // Здесь можно добавить Android-specific зависимости
        }
    }
}
  • Использование многоплатформенных библиотек: Ключевой момент. Библиотеки типа kotlinx.coroutines, ktor, kotlinx.serialization сами используют механизм expect/actual, предоставляя общий API в common и нативные реализации для платформ.

4. Особенности работы с ресурсами и файлами

  • Работа с файлами: Используется общий API kotlin.io, но реальные пути и доступ к файловой системе сильно различаются. Для сложных операций часто требуется expect/actual.
  • Ресурсы (изображения, строки локализации): Не имеют единого механизма в common коде. Часто используются следующие подходы:
    *   **Общие данные**: хранить raw данные (JSON, XML) и парсить их в common коде.
    *   **Платформенные ресурсы**: объявить `expect fun getImageResource(id: String)` и загружать ресурсы через платформенные API (Android `Resources`, iOS `UIImage`).
    *   **Сторонние решения**: библиотеки, например, для локализации, которые сами являются multiplatform.

5. Тестирование common кода

  • Common тесты: можно писать тесты в commonTest, используя kotlin.test. Эти тесты будут выполняться на всех платформах.
import kotlin.test.Test
import kotlin.test.assertTrue

class CommonLogicTest {
    @Test
    fun testCommonCalculation() {
        val result = CommonCalculator().add(2, 3)
        assertTrue(result == 5)
    }
}
  • Mocking платформенных actual реализаций: Для тестирования common кода, который зависит от expect declarations, нужно предоставить actual реализации в тестовой среде. Это может быть упрощенная "mock" реализация в commonTest или использование специальных тестовых source sets.

6. Оптимизации и производительность

  • Избегание тяжелых вычислений в common коде: Common код компилируется в разные цели (JVM bytecode, JavaScript, Native). Следует избегать операций, которые могут быть эффективны на одной платформе, но дороги на другой.
  • Использование inline классов и функций: Помогает уменьшить overhead, особенно при компиляции в Native.
  • Внимание к memory моделям: Kotlin/Native имеет строгую memory модель с запретом shared mutable state между потоками. При использовании kotlinx.coroutines в common коде для iOS цели нужно учитывать это (использовать Dispatchers.Main для UI, избегать неконтролируемого shared state).

Вывод: Common код в KMP — это тщательно продуманный интерфейс и бизнес-логика, абстрагированные от платформ через механизм expect/actual. Его успешная разработка требует дисциплины в соблюдении границ, глубокого понимания доступных многоплатформенных библиотек и продуманной архитектуры, которая позволит максимально вынести в common модуль, оставив платформам только необходимые реализации UI и низкоуровневых системных операций.

Какие знаешь особенности common code в Kotlin Multiplatform? | PrepBro