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

Можно ли использовать библиотеки Swift в Kotlin Multiplatform?

3.0 Senior🔥 41 комментариев
#Android компоненты

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

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

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

Совместимость Swift и Kotlin Multiplatform: Прямое использование библиотек Swift

Нет, напрямую использовать библиотеки, написанные на Swift, в Kotlin Multiplatform (KMP) проектах — нельзя. Это фундаментальное ограничение, обусловленное архитектурными различиями и целями самой технологии KMP.

Почему прямое использование невозможно?

  1. Разные языки и экосистемы:
    *   **Kotlin/Native**, который отвечает за компиляцию Kotlin-кода в нативные iOS-бинарники, использует собственный **менеджер памяти** (сборщик мусора, отличный от ARC в Swift) и свою **систему типов**.
    *   Библиотека на Swift скомпилирована в машинный код, ожидающий определенные соглашения о вызовах (calling conventions), структуры времени выполнения (Swift Runtime) и управление памятью (ARC). Kotlin/Native имеет свою собственную среду выполнения (KN Runtime), которая с ними несовместима напрямую.

  1. Цель KMP — общий код, а не смешивание произвольных зависимостей: Идеология KMP заключается в том, чтобы вы писали бизнес-логику, алгоритмы, сетевые слои и т.д. на Kotlin, а затем компилировали их в общую библиотеку (framework .framework или .xcframework), которую уже используете в нативных iOS (Swift) и Android (Kotlin/Java) проектах. Общий код — это поставщик API для нативных частей, а не потребитель нативных iOS-библиотек.

Стратегии взаимодействия со Swift-кодом в KMP-проектах

Хотя прямого импорта Swift-пакета нет, существует несколько четких и рабочих стратегий для взаимодействия.

1. Создание оберток (объявлений) на Kotlin для Objective-C API (чаще всего)

Это основной и рекомендуемый способ. Большинство iOS-библиотек (включая написанные на Swift с атрибутом @objc) предоставляют Objective-C API (заголовки .h). Kotlin/Native умеет с ними работать через механизм cinterop.

Как это работает:

  1. Вы создаете файл .def, в котором описываете, какие заголовочные файлы (*.h) нужно обработать.
  2. Gradle-плагин KMP использует инструмент cinterop, который парсит Objective-C заголовки и генерирует для них Kotlin-обертки (объявления).
  3. В вашем общем Kotlin-коде вы можете вызывать эти сгенерированные Kotlin-обертки, которые транслируются в вызовы нативного Objective-C/Swift-кода.

Пример build.gradle.kts:

kotlin {
    iosX64() {
        compilations.main {
            cinterops {
                val mySwiftLib by creating {
                    // Указываем путь к заголовкам библиотеки
                    defFile(project.file("src/nativeInterop/cinterop/MySwiftLib.def"))
                    // Опционально: настройки компиляции
                    compilerOpts("-framework", "MySwiftFramework", "-F/path/to/frameworks")
                }
            }
        }
    }
}

Пример MySwiftLib.def:

language = Objective-C
// Импортируем заголовок, который предоставляет публичный Objective-C интерфейс
headers = MySwiftLib/MySwiftLib.h
// Если нужны дополнительные флаги линковки
linkerOpts = -framework MySwiftFramework -F/path/to/frameworks

После этого в Kotlin-коде можно будет писать: MySwiftLib.someFunction().

2. Использование мультиплатформенных аналогов

Часто задача, решаемая Swift-библиотекой, уже имеет Kotlin-аналог, который работает на всех платформах. Это наиболее предпочтительный путь, так как он полностью соответствует философии KMP.

  • Сеть: Вместо Alamofire используйте ktor-client.
  • Сериализация JSON: Вместо SwiftyJSON используйте kotlinx.serialization.
  • DI (Внедрение зависимостей): Вместо Swinject рассмотрите Koin (поддерживает KMP) или Kodein-DI.
  • Асинхронность: Kotlin Coroutines с библиотекой kotlinx.coroutines — единая модель для всех платформ.

3. Вынос зависимости в нативный iOS-слой

Если библиотека сугубо специфична для UI или платформы (например, Lottie для анимаций, Keychain для безопасного хранения), её следует использовать только в нативной iOS-части вашего приложения.

  • Вы пишете общий expect-класс или интерфейс в KMP-модуле.
  • В нативном iOS-исходнике (в iosMain или iosApp) вы предоставляете actual-реализацию, которая внутри уже использует нужную Swift-библиотеку.

Пример:

В общем модуле (commonMain):

// Объявляем ожидаемый функционал
expect class SecureStorage() {
    fun save(key: String, value: String)
    fun read(key: String): String?
}

В iOS-модуле (iosMain):

import platform.Foundation.NSUserDefaults // или обертка для Keychain через cinterop

actual class SecureStorage actual constructor() {
    actual fun save(key: String, value: String) {
        // Используем нативные iOS API или, например, Swift-библиотеку KeychainSwift
        // через созданную ранее cinterop-обертку
        NSUserDefaults.standardUserDefaults.setObject(value, forKey = key)
    }
    actual fun read(key: String): String? {
        return NSUserDefaults.standardUserDefaults.stringForKey(key)
    }
}

Ключевой вывод

Прямого импорта Swift-пакетов в build.gradle.kts по аналогии с implementation("com.squareup.okhttp3:okhttp:4.x.x") не существует. Весь мост между Kotlin Multiplatform и миром Apple строится через:

  1. Objective-C C-Interop (для низкоуровневых и системных библиотек).
  2. Архитектурное разделение на expect/actual.
  3. Выбор мультиплатформенных Kotlin-библиотек.

Таким образом, вы не "используете Swift-библиотеку в Kotlin", а "заставляете общий Kotlin-код взаимодействовать с нативным iOS-слоем, который, в свою очередь, может использовать любые Swift-библиотеки". Это требует дополнительных усилий по настройке и написанию оберток, но предоставляет полный контроль над нативной интеграцией.