Руководство

Как собрать iOS-приложение проекта Kotlin Multiplatform без Mac

В Kotlin Multiplatform большая часть приложения живёт в общем коде на Kotlin. Его можно писать на Windows или Linux. iOS-фреймворку и приложению Xcode всё равно нужна macOS. Мы проверили это 19 октября 2026 года на официальном шаблоне KMP от JetBrains. Ниже то, что прошло, и одна ловушка.

Что работает на Windows и Linux

В документации Kotlin сказано, что с общим кодом и со всеми платформами, кроме iOS, можно работать на любой системе. Мы проверили это на KMP-App-Template, официальном шаблоне команды Kotlin на GitHub. Это приложение Compose Multiplatform для Android, iOS, десктопа и веба. На раннерах Windows и Ubuntu прошла такая команда:

./gradlew :shared:compileKotlinJvm :androidApp:assembleDebug

Общий код скомпилировался для JVM, и приложение для Android собралось. Тесты для Android, десктопа и JVM запускаются так же. Пишите там бизнес-логику и интерфейс на Compose и проверяйте их на Android.

Ловушка: зелёная сборка без iOS-фреймворка

Потом мы попросили раннеры Windows и Ubuntu собрать iOS-фреймворк. Gradle скомпилировал Kotlin для iOS, а шаг линковки пропустил. И всё равно сообщил об успехе:

> Task :shared:compileKotlinIosSimulatorArm64
> Task :shared:linkDebugFrameworkIosSimulatorArm64 SKIPPED
BUILD SUCCESSFUL in 27s

Фреймворк так и не появился. Страница Kotlin о поддержке целей объясняет почему. Linux и Windows умеют делать библиотеки Kotlin для целей Apple. Итоговые бинарные файлы для целей Apple там собрать нельзя. Шаг конфигурации тоже предупредил, что тестам в симуляторе iOS нужна macOS.

Что требует macOS

  • Линковка фреймворка. iOS-приложение подключает общий код как фреймворк, и слинковать его может только Mac.
  • Проект iosApp. Это обычный проект Xcode. Его фаза сборки вызывает Gradle, чтобы встроить фреймворк.
  • Тесты iOS и симулятор. Обоим нужен Xcode.
  • CocoaPods и другой cinterop. По документации Kotlin, им нужна macOS даже для библиотек.

Команды на Mac

На Mac от MacRun есть Xcode 27.1 и Xcode 26.6. JDK там нет, поэтому сначала поставьте его. Мы использовали Zulu JDK 21. В кратком руководстве Kotlin сказано один раз открыть Xcode до первой сборки, чтобы он закончил настройку. Потом клонируйте репозиторий и слинкуйте фреймворк для симулятора:

./gradlew :shared:linkDebugFrameworkIosSimulatorArm64

Затем соберите проект iosApp под симулятор. Эти флаги совпадают с CI-файлом самого шаблона. CODE_SIGNING_ALLOWED=NO пропускает подпись, она не нужна для сборки под симулятор.

cd iosApp
xcodebuild -project iosApp.xcodeproj -scheme iosApp \
  -configuration Debug -sdk iphonesimulator -arch arm64 \
  -derivedDataPath build CODE_SIGNING_ALLOWED=NO build

Оставьте -arch arm64. В первой попытке мы вместо этого указали общее назначение для симулятора. Тогда Xcode попросил у Gradle ещё и срез для симулятора на Intel, и сборка упала:

Xcode requested target architectures that are not configured in your Gradle build: ios_x64.

Шаблон определяет только iosArm64 и iosSimulatorArm64. Указать сразу -destination и -arch тоже не вышло. Xcode ответил, что назначение уже задаёт архитектуру.

Чтобы открыть приложение, загрузите симулятор и поставьте сборку. Используйте свой bundle ID. На MacRun среда iOS 27.1 добавляет устройство iPhone Duo.

xcrun simctl list devices available
xcrun simctl boot "iPhone Duo"
xcrun simctl install booted "build/Build/Products/Debug-iphonesimulator/KMP App.app"
xcrun simctl launch booted com.jetbrains.kmpapp.KMP-App-Template

Можно также открыть iosApp.xcodeproj в Xcode через демонстрацию экрана. Укажите свою команду и нажмите Run. Про удалённый экран из Windows читайте в руководстве Xcode из Windows.

Workflow, который мы запустили на GitHub Actions

Это задача для macOS из нашего теста. Она закрепляет шаблон на одном коммите, так что её можно запустить как есть. В своём репозитории вместо этого получите свой код.

name: kmp-ios
on: workflow_dispatch
env:
  TEMPLATE_SHA: 6b6d09e4f3f5e845116422d59b658791ed6149c6
jobs:
  macos:
    runs-on: macos-26
    steps:
      - uses: actions/checkout@v4
        with:
          repository: Kotlin/KMP-App-Template
          ref: ${{ env.TEMPLATE_SHA }}
      - uses: actions/setup-java@v4
        with:
          distribution: zulu
          java-version: 21
      - run: xcodebuild -version && sw_vers && java -version
      - name: Link the iOS simulator framework
        run: time ./gradlew :shared:linkDebugFrameworkIosSimulatorArm64
      - name: Build the iosApp for the Simulator
        run: |
          time xcodebuild -project iosApp.xcodeproj -scheme iosApp \
            -configuration Debug -sdk iphonesimulator -arch arm64 \
            -derivedDataPath build CODE_SIGNING_ALLOWED=NO build
        working-directory: iosApp
      - name: Install and launch in the Simulator
        run: |
          APP=$(ls -d build/Build/Products/Debug-iphonesimulator/*.app | head -1)
          UDID=$(xcrun simctl list devices available -j | python3 -c "import json,sys; d=json.load(sys.stdin)['devices']; print(next(x['udid'] for k,v in d.items() if 'iOS' in k for x in v if x['name'].startswith('iPhone')))")
          xcrun simctl boot "$UDID"
          xcrun simctl bootstatus "$UDID"
          xcrun simctl install booted "$APP"
          xcrun simctl launch booted com.jetbrains.kmpapp.KMP-App-Template
          sleep 10
          xcrun simctl io booted screenshot shot.png && ls -la shot.png
        working-directory: iosApp

Задача заняла 6 минут 35 секунд. Линковка в Gradle на холодном раннере заняла 4 минуты 7 секунд, в основном на загрузку тулчейна Kotlin/Native. Шаг xcodebuild занял 26 секунд. Эти строки взяты из лога:

Xcode 26.6
Build version 17F113
openjdk version "21.0.12" 2026-07-21 LTS
BUILD SUCCESSFUL in 4m 4s
263M	shared/build/bin/iosSimulatorArm64/debugFramework/Shared.framework
** BUILD SUCCEEDED **
 59M	build/Build/Products/Debug-iphonesimulator/KMP App.app
com.jetbrains.kmpapp.KMP-App-Template: 26325

Последняя строка означает, что приложение работает в симуляторе. Наш запуск шёл на Xcode 26.6, потому что в образе GitHub нет Xcode 27. На Mac от MacRun то же самое даёт sudo xcode-select -s /Applications/Xcode.app, там это Xcode 26.6.

Отправка в TestFlight

Релизная сборка делается в проекте iosApp, как у любого iOS-приложения. Укажите команду в Xcode, создайте архив и загрузите его в App Store Connect. Наше руководство по публикации описывает подпись, API-ключи и проверку. Эти шаги мы не проверяли, потому что у раннера не было аккаунта Apple. На настоящий iPhone ставьте из TestFlight. Удалённый Mac не видит телефон, подключённый к вашему PC.

Кому не стоит арендовать для этого Mac

Если сборка нужна только чтобы убедиться, что iOS ещё компилируется, используйте CI. Workflow выше работает на раннере macOS в GitHub Actions с поминутной оплатой. Личные аккаунты Codemagic получают 500 бесплатных минут сборки на macOS в месяц. Если вы работаете с iOS каждый день, свой Mac за год может обойтись дешевле.

Арендуйте Mac, когда iOS-приложение нужно увидеть. Это интерфейс Compose на настоящем экране iOS, сбой в Xcode или проблема с подписью. Суточный доступ MacRun стоит $15 за выделенный Mac mini на M6, а неделя стоит $59. Вы платите один раз, и ничего не продлевается. В конце Mac очищается, поэтому сначала отправьте работу в git.

Частые вопросы

Можно ли собрать iOS-приложение проекта Kotlin Multiplatform на Windows?

+

Нет. В документации Kotlin сказано, что итоговые бинарные файлы для целей Apple нельзя собрать на Linux или Windows. Общий код, Android и цели JVM там собираются нормально. iOS-фреймворку и приложению Xcode нужен Mac.

Почему Gradle пишет BUILD SUCCESSFUL для iOS на Windows?

+

На Linux и Windows Gradle пропускает задачи линковки для Apple, а не падает. В нашем тесте linkDebugFrameworkIosSimulatorArm64 вывел SKIPPED, и Gradle всё равно сообщил об успехе. Фреймворк не появился.

Можно ли писать интерфейс на Compose Multiplatform в Windows?

+

Да. В нашем тесте общий код шаблона скомпилировался для JVM, а его приложение для Android собралось на Windows. Mac нужен только чтобы собрать и запустить интерфейс на iOS.

Как исправить ошибку "Xcode Requested Architecture Not Configured in Gradle"?

+

Собирайте под одну архитектуру. Мы передали xcodebuild флаги -sdk iphonesimulator -arch arm64, как делает CI самого шаблона KMP. Общее назначение для симулятора просило ещё и x86_64, а шаблон его не определяет.

Сколько длится сборка Kotlin Multiplatform под iOS?

+

На раннере GitHub macos-26 линковка фреймворка шаблона для симулятора заняла около 4 минут на холодном раннере. Потом сборка iosApp в Xcode заняла 26 секунд.

Установлен ли JDK на Mac от MacRun?

+

Нет. Установлены Xcode 27.1, Xcode 26.6 и симулятор iOS 27.1. У вас есть права администратора и Homebrew, так что JDK и всё остальное вы ставите сами.

Похожие руководства