Spec-Zone.ru › Kotlin 2

Kotlin/Native в виде фреймворка Apple — руководство

Импорт библиотек Objective-C находится в статусе Beta. Все объявления Kotlin, сгенерированные инструментом cinterop на основе библиотек Objective-C, должны иметь аннотацию @ExperimentalForeignApi.

Для платформенных библиотек Native, поставляемых с Kotlin/Native (например, Foundation, UIKit и POSIX), opt-in требуется только для некоторых API.

Kotlin/Native обеспечивает двустороннюю совместимость со Swift/Objective-C. Вы можете использовать фреймворки и библиотеки Objective-C в коде Kotlin, а модули Kotlin — в коде Swift/Objective-C.

Kotlin/Native поставляется с набором предварительно импортированных системных фреймворков; также можно импортировать существующий фреймворк и использовать его из Kotlin. В этом руководстве вы узнаете, как создать собственный фреймворк и использовать код Kotlin/Native в приложениях Swift/Objective-C для macOS и iOS.

В этом руководстве вы научитесь:

  • Создавать библиотеку Kotlin и компилировать ее в фреймворк

  • Изучать сгенерированный код API Swift/Objective-C

  • Использовать фреймворк из Objective-C

  • Использовать фреймворк из Swift

Для создания фреймворка Kotlin можно использовать командную строку напрямую или с помощью файла сценария (например, файла .sh или .bat). Однако такой подход плохо подходит для крупных проектов с сотнями файлов и библиотек. Система сборки упрощает процесс, загружая и кэшируя двоичные файлы компилятора Kotlin/Native и библиотеки с транзитивными зависимостями, а также запуская компилятор и тесты. Kotlin/Native может использовать систему сборки Gradle с помощью плагина Kotlin Multiplatform.

Если вы пользуетесь Mac и хотите создавать и запускать приложения для iOS или других платформ Apple, сначала установите инструменты командной строки Xcode, запустите их и примите условия лицензии.

Создание библиотеки Kotlin

Подробные сведения о первых шагах, создании нового проекта Kotlin/Native и его открытии в IntelliJ IDEA см. в руководстве Начало работы с Kotlin/Native.

Компилятор Kotlin/Native может создать из кода Kotlin фреймворк для macOS и iOS. Созданный фреймворк содержит все объявления и двоичные файлы, необходимые для его использования со Swift/Objective-C.

Сначала создадим библиотеку Kotlin:

  1. В каталоге src/nativeMain/kotlin создайте файл lib.kt с содержимым библиотеки:

    package example
    
    object Object {
        val field = "A"
    }
    
    interface Interface {
        fun iMember() {}
    }
    
    class Clazz : Interface {
        fun member(p: Int): ULong? = 42UL
    }
    
    fun forIntegers(b: Byte, s: UShort, i: Int, l: ULong?) { }
    fun forFloats(f: Float, d: Double?) { }
    
    fun strings(str: String?) : String {
        return "That is '$str' from C"
    }
    
    fun acceptFun(f: (String) -> String?) = f("Kotlin/Native rocks!")
    fun supplyFun() : (String) -> String? = { "$it is cool!" }
    
  2. Обновите файл сборки Gradle build.gradle(.kts) следующим образом:

    import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
    
    plugins {
        kotlin("multiplatform") version "2.4.20"
    }
    
    repositories {
        mavenCentral()
    }
    
    kotlin {
        iosArm64()
        // macosArm64()
        // iosSimulatorArm64()
    
        targets.withType<KotlinNativeTarget>().configureEach {
            binaries {
                framework {
                    baseName = "Demo"
                }
            }
        }
    }
    
    tasks.wrapper {
        gradleVersion = "9.7.0"
        distributionType = Wrapper.DistributionType.ALL
    }
    
    import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
    
    plugins {
        id 'org.jetbrains.kotlin.multiplatform' version '2.4.20'
    }
    
    repositories {
        mavenCentral()
    }
    
    kotlin {
        iosArm64()
        // macosArm64()
        // iosSimulatorArm64()
    
        targets.withType(KotlinNativeTarget).configureEach {
            binaries {
                framework {
                    baseName = "Demo"
                }
            }
        }
    }
    
    wrapper {
        gradleVersion = "9.7.0"
        distributionType = "ALL"
    }
    

    Блок binaries {} настраивает проект для создания динамической или общей библиотеки.

    Kotlin/Native поддерживает цели iosArm64 и iosSimulatorArm64 для iOS, а также цель macosArm64 для macOS. Поэтому вместо iosArm64() можно использовать соответствующую функцию Gradle для целевой платформы:

    Целевая платформа/устройство

    Функция Gradle

    macOS ARM64

    macosArm64()

    iOS ARM64

    iosArm64()

    Симулятор iOS (ARM64)

    iosSimulatorArm64()

    Сведения о других поддерживаемых целевых платформах Apple см. в разделе Поддержка целевых платформ Kotlin/Native.

  3. Чтобы собрать фреймворк, запустите задачу Gradle linkDebugFramework<YourTargetName> в IDE или выполните в терминале команду, например:

    ./gradlew linkDebugFrameworkIosArm64
    

В результате сборки фреймворк будет создан в каталоге build/bin/<yourTargetName>/debugFramework.

Для создания вариантов фреймворка debug и release можно также использовать общую задачу Gradle link<YourTargetName>.

Заголовки сгенерированного фреймворка

Каждый вариант фреймворка содержит файл заголовка. Заголовки не зависят от целевой платформы. Файлы заголовков содержат определения вашего кода Kotlin и несколько общих объявлений Kotlin. Посмотрим, что в них находится.

Объявления среды выполнения Kotlin/Native

Откройте файл заголовка Demo.h в каталоге build/bin/<yourTargetName>/debugFramework/Demo.framework/Headers. Ознакомьтесь с объявлениями среды выполнения Kotlin:

NS_ASSUME_NONNULL_BEGIN
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-warning-option"
#pragma clang diagnostic ignored "-Wincompatible-property-type"
#pragma clang diagnostic ignored "-Wnullability"

#pragma push_macro("_Nullable_result")
#if !__has_feature(nullability_nullable_result)
#undef _Nullable_result
#define _Nullable_result _Nullable
#endif

__attribute__((swift_name("KotlinBase")))
@interface DemoBase : NSObject
- (instancetype)init __attribute__((unavailable));
+ (instancetype)new __attribute__((unavailable));
+ (void)initialize __attribute__((objc_requires_super));
@end

@interface DemoBase (DemoBaseCopying) <NSCopying>
@end

__attribute__((swift_name("KotlinMutableSet")))
@interface DemoMutableSet<ObjectType> : NSMutableSet<ObjectType>
@end

__attribute__((swift_name("KotlinMutableDictionary")))
@interface DemoMutableDictionary<KeyType, ObjectType> : NSMutableDictionary<KeyType, ObjectType>
@end

@interface NSError (NSErrorDemoKotlinException)
@property (readonly) id _Nullable kotlinException;
@end

В Swift/Objective-C у классов Kotlin есть базовый класс KotlinBase, который наследуется от класса NSObject. Также имеются обертки для коллекций и исключений. Большинство типов коллекций сопоставляются с похожими типами коллекций в Swift/Objective-C:

Kotlin

Swift

Objective-C

List

Array

NSArray

MutableList

NSMutableArray

NSMutableArray

Set

Set

NSSet

MutableSet

NSMutableSet

NSMutableSet

Map

Dictionary

NSDictionary

MutableMap

NSMutableDictionary

NSMutableDictionary

Числа Kotlin и NSNumber

Следующая часть файла Demo.h содержит сопоставления типов между числовыми типами Kotlin/Native и NSNumber. В Objective-C базовый класс называется DemoNumber, а в Swift — KotlinNumber. Он наследуется от NSNumber.

Для каждого числового типа Kotlin предусмотрен соответствующий предварительно объявленный дочерний класс:

Kotlin

Swift

Objective-C

Простой тип

-

KotlinNumber

<Package>Number

-

Byte

KotlinByte

<Package>Byte

char

UByte

KotlinUByte

<Package>UByte

unsigned char

Short

KotlinShort

<Package>Short

short

UShort

KotlinUShort

<Package>UShort

unsigned short

Int

KotlinInt

<Package>Int

int

UInt

KotlinUInt

<Package>UInt

unsigned int

Long

KotlinLong

<Package>Long

long long

ULong

KotlinULong

<Package>ULong

unsigned long long

Float

KotlinFloat

<Package>Float

float

Double

KotlinDouble

<Package>Double

double

Boolean

KotlinBoolean

<Package>Boolean

BOOL/Bool

Для каждого числового типа предусмотрен метод класса, создающий новый экземпляр из соответствующего простого типа. Также есть метод экземпляра, позволяющий извлечь обратно простое значение. Схематически все такие объявления выглядят так:

__attribute__((swift_name("Kotlin__TYPE__")))
@interface Demo__TYPE__ : DemoNumber
- (instancetype)initWith__TYPE__:(__CTYPE__)value;
+ (instancetype)numberWith__TYPE__:(__CTYPE__)value;
@end;

Здесь __TYPE__ — одно из названий простых типов, а __CTYPE__ — соответствующий тип Objective-C, например initWithChar(char).

Эти типы используются для сопоставления упакованных числовых типов Kotlin со Swift/Objective-C. В Swift можно вызвать конструктор, чтобы создать экземпляр, например KotlinLong(value: 42).

Классы и объекты из Kotlin

Посмотрим, как class и object сопоставляются со Swift/Objective-C. Сгенерированный файл Demo.h содержит точные определения для Class, Interface и Object:

__attribute__((swift_name("Interface")))
@protocol DemoInterface
@required
- (void)iMember __attribute__((swift_name("iMember()")));
@end

__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("Clazz")))
@interface DemoClazz : DemoBase <DemoInterface>
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
- (DemoULong * _Nullable)memberP:(int32_t)p __attribute__((swift_name("member(p:)")));
@end

__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("Object")))
@interface DemoObject : DemoBase
+ (instancetype)alloc __attribute__((unavailable));
+ (instancetype)allocWithZone:(struct _NSZone *)zone __attribute__((unavailable));
+ (instancetype)object __attribute__((swift_name("init()")));
@property (class, readonly, getter=shared) DemoObject *shared __attribute__((swift_name("shared")));
@property (readonly) NSString *field __attribute__((swift_name("field")));
@end

Атрибуты Objective-C в этом коде позволяют использовать фреймворк как из Swift, так и из Objective-C. Для Interface, Clazz и Object создаются соответственно DemoInterface, DemoClazz и DemoObject.

Interface преобразуется в @protocol, а class и object представлены как @interface. Префикс Demo образован от имени фреймворка. Тип возвращаемого значения с возможностью null ULong? преобразуется в DemoULong в Objective-C.

Глобальные объявления из Kotlin

Все глобальные функции Kotlin преобразуются в DemoLibKt в Objective-C и в LibKt в Swift, где Demo — это имя фреймворка, заданное параметром -output функции kotlinc-native:

__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("LibKt")))
@interface DemoLibKt : DemoBase
+ (NSString * _Nullable)acceptFunF:(NSString * _Nullable (^)(NSString *))f __attribute__((swift_name("acceptFun(f:)")));
+ (void)forFloatsF:(float)f d:(DemoDouble * _Nullable)d __attribute__((swift_name("forFloats(f:d:)")));
+ (void)forIntegersB:(int8_t)b s:(uint16_t)s i:(int32_t)i l:(DemoULong * _Nullable)l __attribute__((swift_name("forIntegers(b:s:i:l:)")));
+ (NSString *)stringsStr:(NSString * _Nullable)str __attribute__((swift_name("strings(str:)")));
+ (NSString * _Nullable (^)(NSString *))supplyFun __attribute__((swift_name("supplyFun()")));
@end

Тип Kotlin String и тип Objective-C NSString* сопоставляются напрямую. Аналогично, тип Unit из Kotlin сопоставляется с void. Примитивные типы сопоставляются напрямую. Типы-примитивы, не допускающие null, сопоставляются напрямую. Типы-примитивы, допускающие null, сопоставляются с типами Kotlin<TYPE>*, как показано в таблице. Включены обе функции высшего порядка — acceptFunF и supplyFun; они принимают блоки Objective-C.

Дополнительные сведения о сопоставлении типов см. в разделе Совместимость со Swift/Objective-C.

Сборка мусора и подсчет ссылок

В Swift и Objective-C используется автоматический подсчет ссылок (ARC). У Kotlin/Native есть собственный сборщик мусора, который также интегрирован с ARC Swift/Objective-C.

Неиспользуемые объекты Kotlin удаляются автоматически. Вам не нужно предпринимать дополнительные действия для управления временем жизни экземпляров Kotlin/Native из Swift или Objective-C.

Использование кода из Objective-C

Вызовем фреймворк из Objective-C. В каталоге фреймворка создайте файл main.m со следующим кодом:

#import <Foundation/Foundation.h>
#import <Demo/Demo.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        [DemoObject.shared field];
        
        DemoClazz* clazz = [[ DemoClazz alloc] init];
        [clazz memberP:42];
        
        [DemoLibKt forIntegersB:1 s:1 i:3 l:[DemoULong numberWithUnsignedLongLong:4]];
        [DemoLibKt forIntegersB:1 s:1 i:3 l:nil];
        
        [DemoLibKt forFloatsF:2.71 d:[DemoDouble numberWithDouble:2.71]];
        [DemoLibKt forFloatsF:2.71 d:nil];
        
        NSString* ret = [DemoLibKt acceptFunF:^NSString * _Nullable(NSString * it) {
            return [it stringByAppendingString:@" Kotlin is fun"];
        }];
        
        NSLog(@"%@", ret);
        return 0;
    }
}

Здесь вы вызываете классы Kotlin непосредственно из кода Objective-C. Для доступа к объекту Kotlin используется свойство класса <object name>.shared, которое позволяет получить единственный экземпляр объекта и вызвать его методы.

Для создания экземпляра класса Clazz используется распространенный шаблон. В Objective-C вызывается [[ DemoClazz alloc] init]. Для конструкторов без параметров также можно использовать [DemoClazz new].

Глобальные объявления из исходного кода Kotlin в Objective-C находятся в области видимости класса DemoLibKt. Все функции Kotlin преобразуются в методы класса этого класса.

Функция strings преобразуется в функцию Objective-C DemoLibKt.stringsStr, поэтому вы можете передать ей непосредственно NSString. Возвращаемое значение также доступно как NSString.

Использование кода из Swift

В созданном вами фреймворке есть вспомогательные атрибуты, упрощающие его использование со Swift. Преобразуем предыдущий пример на Objective-C в код Swift.

В каталоге фреймворка создайте файл main.swift со следующим кодом:

import Foundation
import Demo

let kotlinObject = Object.shared

let field = Object.shared.field

let clazz = Clazz()
clazz.member(p: 42)

LibKt.forIntegers(b: 1, s: 2, i: 3, l: 4)
LibKt.forFloats(f: 2.71, d: nil)

let ret = LibKt.acceptFun { "\($0) Kotlin is fun" }
if (ret != nil) {
    print(ret!)
}

Между исходным кодом Kotlin и его версией на Swift есть несколько небольших различий. В Kotlin у любого объявления объекта есть только один экземпляр. Для доступа к этому единственному экземпляру используется синтаксис Object.shared.

Имена функций и свойств Kotlin переносятся без изменений. String из Kotlin преобразуется в String в Swift. Swift также скрывает упаковку NSNumber*. Кроме того, в Kotlin можно передать замыкание Swift и вызвать из Swift лямбда-функцию Kotlin.

Дополнительные сведения о сопоставлении типов см. в разделе Совместимость со Swift/Objective-C.

Подключение фреймворка к проекту iOS

Теперь вы можете подключить созданный фреймворк к проекту iOS в качестве зависимости. Настроить и автоматизировать процесс можно несколькими способами — выберите наиболее подходящий для вас:

Выбрать способ интеграции с iOS

Что дальше

  • Подробнее о совместимости с Objective-C

  • Узнайте, как в Kotlin реализована совместимость с C

  • Ознакомьтесь с руководством по использованию Kotlin/Native в виде динамической библиотеки

01 сентября 2026
Совместимость со Swift/Objective-CСовместимость со Swift с помощью Swift export

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/apple-framework.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API