Сборка финальных нативных бинарных файлов
По умолчанию цель Kotlin/Native компилируется в артефакт библиотеки *.klib, который может использоваться самим Kotlin/Native как зависимость, но не может быть запущен или использован в качестве нативной библиотеки.
Чтобы объявить финальные нативные бинарные файлы, например исполняемые файлы или динамические библиотеки, используйте свойство binaries нативной цели. Это свойство представляет собой коллекцию нативных бинарных файлов, собираемых для этой цели в дополнение к артефакту *.klib, создаваемому по умолчанию, и предоставляет набор методов для их объявления и настройки.
Бинарные файлы, созданные компилятором Kotlin/Native, могут содержать сторонний код, данные или производные работы. Поэтому при распространении финального бинарного файла, скомпилированного Kotlin/Native, всегда включайте необходимые файлы лицензий в дистрибутив с бинарными файлами.
Объявление бинарных файлов
Используйте следующие фабричные методы, чтобы объявить элементы коллекции binaries.
Фабричный метод |
Тип бинарного файла |
Доступно для |
|---|---|---|
|
Исполняемый файл приложения |
Всех нативных целей |
|
Исполняемый файл тестов |
Всех нативных целей |
|
Динамическая нативная библиотека |
Всех нативных целей |
|
Статическая нативная библиотека |
Всех нативных целей |
|
Фреймворк Objective-C |
Только целей macOS, iOS, watchOS и tvOS |
В простейшем варианте дополнительные параметры не требуются, а для каждого типа сборки создается один бинарный файл. Сейчас доступны два типа сборки:
DEBUG— создает неоптимизированный бинарный файл с дополнительными метаданными, полезными при работе с инструментами отладкиRELEASE— создает оптимизированный бинарный файл без отладочной информации
Следующий фрагмент кода создает два исполняемых бинарных файла: для отладки и выпуска:
kotlin {
linuxX64 { // Define your target instead.
binaries {
executable {
// Binary configuration.
}
}
}
}
Если дополнительная настройка не требуется, лямбду можно опустить:
binaries {
executable()
}
Можно указать, для каких типов сборки создавать бинарные файлы. В следующем примере создается только исполняемый файл debug:
binaries {
executable(listOf(DEBUG)) {
// Binary configuration.
}
}
binaries {
executable([DEBUG]) {
// Binary configuration.
}
}
Также можно объявлять бинарные файлы с пользовательскими именами:
binaries {
executable("foo", listOf(DEBUG)) {
// Binary configuration.
}
// It's possible to drop the list of build types
// (in this case, all the available build types will be used).
executable("bar") {
// Binary configuration.
}
}
binaries {
executable('foo', [DEBUG]) {
// Binary configuration.
}
// It's possible to drop the list of build types
// (in this case, all the available build types will be used).
executable('bar') {
// Binary configuration.
}
}
Первый аргумент задает префикс имени, который используется как имя бинарного файла по умолчанию. Например, в Windows код создает файлы foo.exe и bar.exe. Также можно использовать префикс имени, чтобы обратиться к бинарному файлу в скрипте сборки.
Доступ к бинарным файлам
К бинарным файлам можно обращаться, чтобы настроить их или получить их свойства (например, путь к выходному файлу).
Получить бинарный файл можно по его уникальному имени. Оно формируется на основе префикса имени (если он указан), типа сборки и типа бинарного файла по шаблону: <optional-name-prefix><build-type><binary-kind>, например, releaseFramework или testDebugExecutable.
// Fails if there is no such binary.
binaries["fooDebugExecutable"]
binaries.getByName("fooDebugExecutable")
// Returns null if there is no such binary.
binaries.findByName("fooDebugExecutable")
// Fails if there is no such binary.
binaries['fooDebugExecutable']
binaries.fooDebugExecutable
binaries.getByName('fooDebugExecutable')
// Returns null if there is no such binary.
binaries.findByName('fooDebugExecutable')
В качестве альтернативы можно получить бинарный файл по префиксу имени и типу сборки с помощью типизированных методов получения.
// Fails if there is no such binary.
binaries.getExecutable("foo", DEBUG)
binaries.getExecutable(DEBUG) // Skip the first argument if the name prefix isn't set.
binaries.getExecutable("bar", "DEBUG") // You also can use a string for build type.
// Similar getters are available for other binary kinds:
// getFramework, getStaticLib and getSharedLib.
// Returns null if there is no such binary.
binaries.findExecutable("foo", DEBUG)
// Similar getters are available for other binary kinds:
// findFramework, findStaticLib and findSharedLib.
// Fails if there is no such binary.
binaries.getExecutable('foo', DEBUG)
binaries.getExecutable(DEBUG) // Skip the first argument if the name prefix isn't set.
binaries.getExecutable('bar', 'DEBUG') // You also can use a string for build type.
// Similar getters are available for other binary kinds:
// getFramework, getStaticLib and getSharedLib.
// Returns null if there is no such binary.
binaries.findExecutable('foo', DEBUG)
// Similar getters are available for other binary kinds:
// findFramework, findStaticLib and findSharedLib.
Экспорт зависимостей в бинарные файлы
При сборке фреймворка Objective-C или нативной библиотеки (динамической или статической) может потребоваться включить в нее не только классы текущего проекта, но и классы его зависимостей. Укажите, какие зависимости нужно экспортировать в бинарный файл, с помощью метода export.
kotlin {
//...
sourceSets {
macosMain.dependencies {
// Will be exported.
api(project(":dependency"))
api("org.example:exported-library:1.0")
// Will not be exported.
api("org.example:not-exported-library:1.0")
}
}
macosArm64("macos").binaries {
framework {
export(project(":dependency"))
export("org.example:exported-library:1.0")
}
sharedLib {
// It's possible to export different sets of dependencies to different binaries.
export(project(':dependency'))
}
}
}
kotlin {
//...
sourceSets {
macosMain.dependencies {
// Will be exported.
api project(':dependency')
api 'org.example:exported-library:1.0'
// Will not be exported.
api 'org.example:not-exported-library:1.0'
}
}
macosArm64("macos").binaries {
framework {
export project(':dependency')
export 'org.example:exported-library:1.0'
}
sharedLib {
// It's possible to export different sets of dependencies to different binaries.
export project(':dependency')
}
}
}
Например, вы реализуете несколько модулей на Kotlin и хотите использовать их из Swift. Использование нескольких фреймворков Kotlin/Native в приложении Swift ограничено, но можно создать объединяющий фреймворк и экспортировать в него все эти модули.
При экспорте зависимости весь ее API включается в API фреймворка. Компилятор добавляет код этой зависимости во фреймворк, даже если используется лишь небольшая его часть. Это отключает удаление неиспользуемого кода для экспортированной зависимости (и в некоторой степени для ее зависимостей).
По умолчанию экспорт не является транзитивным. Это означает, что если вы экспортируете библиотеку foo, зависящую от библиотеки bar, в выходной фреймворк добавляются только методы foo.
Это поведение можно изменить с помощью параметра transitiveExport. Если задать значение true, объявления библиотеки bar также будут экспортированы.
binaries {
framework {
export(project(":dependency"))
// Export transitively.
transitiveExport = true
}
}
binaries {
framework {
export project(':dependency')
// Export transitively.
transitiveExport = true
}
}
Сборка универсальных фреймворков
По умолчанию фреймворк Objective-C, созданный Kotlin/Native, поддерживает только одну платформу. Однако такие фреймворки можно объединить в один универсальный (fat) бинарный файл с помощью инструмента lipo. Это особенно полезно для 32- и 64-разрядных фреймворков iOS. В этом случае полученный универсальный фреймворк можно использовать как на 32-разрядных, так и на 64-разрядных устройствах.
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
kotlin {
// Create and configure the targets.
val watchos32 = watchosArm32("watchos32")
val watchos64 = watchosArm64("watchos64")
configure(listOf(watchos32, watchos64)) {
binaries.framework {
baseName = "MyFramework"
}
}
// Create a task to build a fat framework.
tasks.register<FatFrameworkTask>("debugFatFramework") {
// The fat framework must have the same base name as the initial frameworks.
baseName = "MyFramework"
// The default destination directory is "<build directory>/fat-framework".
destinationDirProperty.set(layout.buildDirectory.dir("fat-framework/debug"))
// Specify the frameworks to be merged.
from(
watchos32.binaries.getFramework("DEBUG"),
watchos64.binaries.getFramework("DEBUG")
)
}
}
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
kotlin {
// Create and configure the targets.
targets {
watchosArm32("watchos32")
watchosArm64("watchos64")
configure([watchos32, watchos64]) {
binaries.framework {
baseName = "MyFramework"
}
}
}
// Create a task building a fat framework.
tasks.register("debugFatFramework", FatFrameworkTask) {
// The fat framework must have the same base name as the initial frameworks.
baseName = "MyFramework"
// The default destination directory is "<build directory>/fat-framework".
destinationDirProperty.set(layout.buildDirectory.dir("fat-framework/debug"))
// Specify the frameworks to be merged.
from(
targets.watchos32.binaries.getFramework("DEBUG"),
targets.watchos64.binaries.getFramework("DEBUG")
)
}
}
Сборка XCFramework
Все проекты Kotlin Multiplatform могут использовать XCFramework в качестве выходного артефакта, чтобы объединить логику для всех целевых платформ и архитектур в одном пакете. В отличие от универсальных (fat) фреймворков, перед публикацией приложения в App Store не нужно удалять все ненужные архитектуры.
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
plugins {
kotlin("multiplatform") version "2.4.20"
}
kotlin {
val xcf = XCFramework()
val iosTargets = listOf(iosArm64(), iosSimulatorArm64())
iosTargets.forEach {
it.binaries.framework {
baseName = "shared"
xcf.add(this)
}
}
}
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkConfig
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '2.4.20'
}
kotlin {
def xcf = new XCFrameworkConfig(project)
def iosTargets = [iosArm64(), iosSimulatorArm64()]
iosTargets.forEach {
it.binaries.framework {
baseName = 'shared'
xcf.add(it)
}
}
}
При объявлении XCFramework плагин Kotlin Gradle зарегистрирует несколько задач Gradle:
assembleXCFrameworkassemble<Framework name>DebugXCFrameworkassemble<Framework name>ReleaseXCFramework
Если в проекте используется интеграция с CocoaPods, XCFramework можно собрать с помощью плагина Kotlin CocoaPods Gradle. Он включает следующие задачи, которые собирают XCFramework со всеми зарегистрированными целями и создают файлы podspec:
podPublishReleaseXCFramework— создает XCFramework для выпуска вместе с файлом podspec.podPublishDebugXCFramework— создает XCFramework для отладки вместе с файлом podspec.podPublishXCFramework— создает XCFramework для отладки и выпуска вместе с файлом podspec.
Это позволяет распространять общие части проекта отдельно от мобильных приложений через CocoaPods. XCFramework также можно использовать для публикации в частных или общедоступных репозиториях podspec.
Настройка файла Info.plist
При создании фреймворка компилятор Kotlin/Native генерирует файл списка информационных свойств Info.plist. Его свойства можно настроить с помощью соответствующих параметров бинарного файла:
Свойство |
Параметр бинарного файла |
|---|---|
|
|
|
|
|
|
Чтобы включить эту возможность, передайте флаг компилятора -Xbinary=$option=$value или задайте DSL Gradle binaryOption("option", "value") для нужного фреймворка:
binaries {
framework {
binaryOption("bundleId", "com.example.app")
binaryOption("bundleVersion", "2")
}
}
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform/multiplatform-build-native-binaries.html