Faça o build do app iOS de um projeto Kotlin Multiplatform sem Mac
Com Kotlin Multiplatform, a maior parte do seu app fica em código Kotlin compartilhado. Você pode escrever esse código no Windows ou no Linux. O framework iOS e o app do Xcode ainda precisam do macOS. Testamos isso em 19 de outubro de 2026, com o template KMP oficial da JetBrains. Abaixo está o que passou, e uma armadilha.
O que funciona no Windows e no Linux
A documentação do Kotlin diz que você pode trabalhar no código compartilhado e em todas as plataformas menos o iOS a partir de qualquer sistema. Conferimos isso com o KMP-App-Template, o template oficial do time do Kotlin no GitHub. É um app Compose Multiplatform para Android, iOS, desktop e web. Nos runners Windows e Ubuntu, isto passou:
./gradlew :shared:compileKotlinJvm :androidApp:assembleDebug
O código compartilhado compilou para a JVM, e o app Android foi gerado. Você pode rodar os testes de Android, desktop e JVM do mesmo jeito. Escreva ali sua lógica de negócio e sua UI em Compose, e confira tudo no Android.
A armadilha: um build verde sem framework iOS
Depois pedimos o framework iOS aos runners Windows e Ubuntu. O Gradle compilou o Kotlin para iOS e pulou a etapa de link. Mesmo assim, informou sucesso:
> Task :shared:compileKotlinIosSimulatorArm64 > Task :shared:linkDebugFrameworkIosSimulatorArm64 SKIPPED BUILD SUCCESSFUL in 27s
Nenhum framework saiu. A página de alvos suportados do Kotlin explica o motivo. Linux e Windows conseguem gerar bibliotecas Kotlin para alvos Apple. Binários finais para alvos Apple não podem ser gerados ali. A etapa de configuração também avisou que os testes no simulador do iOS exigem macOS.
O que precisa do macOS
- O link do framework. O app iOS importa seu código compartilhado como um framework, e só um Mac consegue fazer o link.
- O projeto iosApp. É um projeto Xcode normal. A fase de build dele chama o Gradle para embutir o framework.
- Os testes de iOS e o Simulador. Os dois precisam do Xcode.
- CocoaPods e outros cinterop. A documentação do Kotlin diz que eles precisam de um host macOS, mesmo para bibliotecas.
Os comandos no Mac
Um Mac da MacRun vem com Xcode 27.1 e Xcode 26.6. Ele não tem JDK, então instale um primeiro. Usamos o Zulu JDK 21. O quickstart do Kotlin diz para abrir o Xcode uma vez antes do primeiro build, para ele terminar a configuração. Depois clone seu repositório e faça o link do framework do simulador:
./gradlew :shared:linkDebugFrameworkIosSimulatorArm64
Em seguida faça o build do projeto iosApp para o Simulador. Estas flags são as mesmas do arquivo de CI do próprio template. CODE_SIGNING_ALLOWED=NO pula a assinatura, que um build para o simulador não precisa.
cd iosApp xcodebuild -project iosApp.xcodeproj -scheme iosApp \ -configuration Debug -sdk iphonesimulator -arch arm64 \ -derivedDataPath build CODE_SIGNING_ALLOWED=NO build
Mantenha -arch arm64. Na nossa primeira tentativa usamos um destino genérico de simulador. O Xcode então pediu ao Gradle também uma fatia de simulador Intel, e o build falhou:
Xcode requested target architectures that are not configured in your Gradle build: ios_x64.
O template só define iosArm64 e iosSimulatorArm64. Passar -destination e -arch juntos também falhou. O Xcode disse que o destino já define a arquitetura.
Para abrir o app, ligue um simulador e instale o build. Use o seu próprio bundle ID. Na MacRun, o runtime do iOS 27.1 traz o aparelho 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
Você também pode abrir o iosApp.xcodeproj no Xcode pelo compartilhamento de tela. Defina seu time e clique em Run. A partir do Windows, veja Xcode a partir do Windows para a tela remota.
O fluxo que rodamos no GitHub Actions
Este é o job de macOS do nosso teste. Ele fixa o template em um commit, então você pode rodar do jeito que está. No seu próprio repositório, faça o checkout do seu código.
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: iosAppO job levou 6 minutos e 35 segundos. O link do Gradle levou 4 minutos e 7 segundos em um runner frio, quase tudo baixando o toolchain do Kotlin/Native. A etapa do xcodebuild levou 26 segundos. Estas linhas vêm do log:
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
A última linha é o app rodando no Simulador. Nosso teste usou o Xcode 26.6, porque a imagem do GitHub não tem Xcode 27. Em um Mac da MacRun você pode usar a mesma versão com sudo xcode-select -s /Applications/Xcode.app, que lá é o Xcode 26.6.
Envio para o TestFlight
O build de release acontece no projeto iosApp, como em qualquer app iOS. Defina seu time no Xcode, arquive e envie para o App Store Connect. Nosso guia de publicação explica assinatura, chaves de API e revisão. Não testamos essas etapas, porque nosso runner não tinha conta Apple. Para um iPhone de verdade, instale pelo TestFlight. Um Mac remoto não enxerga um celular ligado ao seu PC.
Quem não deve alugar um Mac para isso
Se você só precisa de um build para provar que o iOS ainda compila, use CI. O fluxo acima roda em um runner macOS do GitHub Actions, cobrado por minuto. As contas pessoais do Codemagic incluem 500 minutos grátis de build em macOS por mês. Se você trabalha com iOS todo dia, um Mac próprio pode sair mais barato em um ano.
Alugue um Mac quando precisar ver o app iOS. Isso quer dizer a UI em Compose em uma tela de iOS de verdade, um crash no Xcode ou um problema de assinatura. Um passe diário da MacRun custa $15 por um Mac mini M6 dedicado, e uma semana custa $59. Você paga uma vez e nada se renova. O Mac é apagado no final, então envie seu trabalho para o git antes.
Perguntas frequentes
Posso fazer o build do app iOS de um projeto Kotlin Multiplatform no Windows?
+
Não. A documentação do Kotlin diz que binários finais para alvos Apple não podem ser gerados no Linux nem no Windows. O código compartilhado e os alvos Android e JVM funcionam bem ali. O framework iOS e o app do Xcode precisam de um Mac.
Por que o Gradle diz BUILD SUCCESSFUL para iOS no Windows?
+
O Gradle pula as tarefas de link da Apple no Linux e no Windows em vez de falhar. No nosso teste, linkDebugFrameworkIosSimulatorArm64 mostrou SKIPPED, e o Gradle ainda informou sucesso. Nenhum framework foi gerado.
Posso escrever UI em Compose Multiplatform no Windows?
+
Sim. No nosso teste, o código compartilhado do template compilou para a JVM e o app Android dele foi gerado no Windows. Você só precisa de um Mac para fazer o build e rodar a UI no iOS.
O que resolve "Xcode Requested Architecture Not Configured in Gradle"?
+
Faça o build para uma só arquitetura. Passamos -sdk iphonesimulator -arch arm64 ao xcodebuild, como faz o próprio CI do template KMP. Um destino genérico de simulador também pediu x86_64, que o template não define.
Quanto tempo leva um build iOS de Kotlin Multiplatform?
+
No runner macos-26 do GitHub, o link do framework de simulador do template levou cerca de 4 minutos em um runner frio. Depois, o build do iosApp no Xcode levou 26 segundos.
Há um JDK instalado em um Mac da MacRun?
+
Não. O Xcode 27.1, o Xcode 26.6 e o simulador do iOS 27.1 estão instalados. Você tem direitos de administrador e Homebrew, então instala o JDK e o que mais precisar.