Guia

Faça o build do seu app .NET MAUI para iOS sem ter um Mac

Você pode escrever um app .NET MAUI no Visual Studio no Windows. O build iOS ainda precisa de um Mac, porque precisa do Xcode. A resposta da Microsoft é o Pair to Mac, que controla um Mac por SSH. Esta página mostra um caminho mais simples que testamos: instale o .NET em um Mac e faça o build com dotnet no terminal dele.

Por que o MAUI precisa de um Mac para iOS

A página do Pair to Mac da Microsoft é direta. O build de apps iOS exige as ferramentas de build da Apple, e elas só rodam em um Mac. O Visual Studio no Windows envia o build para um Mac por SSH. O Mac compila e assina o app.

O antigo atalho acabou. A Microsoft aposentou o Visual Studio for Mac em 31 de agosto de 2024. Em um Mac, agora você usa a linha de comando dotnet, ou um editor como o VS Code com o C# Dev Kit.

O caminho que testamos: dotnet no Mac

Conecte ao Mac por SSH e instale o .NET SDK. Depois adicione o workload do MAUI e faça o build. Nosso teste usou o script de instalação da Microsoft e um app novo criado pelo template do MAUI. Este é o job de build do fluxo, exatamente como passou no runner macos-26 do GitHub em 19 de outubro de 2026.

name: maui-ios
on: workflow_dispatch
jobs:
  build-ios-xcode-26-6:
    runs-on: macos-26
    steps:
      - name: Install .NET SDK 10.0.401 into the home folder
        run: |
          curl -sSL https://dot.net/v1/dotnet-install.sh -o dotnet-install.sh
          bash dotnet-install.sh --version 10.0.401 --install-dir "$HOME/.dotnet"
          echo "DOTNET_ROOT=$HOME/.dotnet" >> "$GITHUB_ENV"
          echo "$HOME/.dotnet" >> "$GITHUB_PATH"
      - run: dotnet --version
      - name: Install the MAUI workload (workload set 10.0.401)
        run: time dotnet workload install maui --version 10.0.401
      - run: dotnet workload --info
      - run: sudo xcode-select -s /Applications/Xcode_26.6.app
      - run: xcodebuild -version && sw_vers
      - run: dotnet new maui -n MauiDemo
      - run: grep -n "TargetFrameworks" MauiDemo/MauiDemo.csproj
      - name: Build for the iOS Simulator (Debug)
        run: time dotnet build -f net10.0-ios -c Debug
        working-directory: MauiDemo
      - name: Build for a device, unsigned (Release, ios-arm64)
        run: time dotnet build -f net10.0-ios -c Release -r ios-arm64 -p:EnableCodeSigning=false
        working-directory: MauiDemo
      - name: Publish for a device, unsigned
        continue-on-error: true
        run: time dotnet publish -f net10.0-ios -c Release -r ios-arm64 -p:EnableCodeSigning=false
        working-directory: MauiDemo
      - run: find bin -maxdepth 5 \( -name "*.app" -o -name "*.ipa" \) -print -exec du -sh {} \;
        working-directory: MauiDemo

No seu próprio Mac, rode os mesmos comandos por SSH. O script de instalação coloca o .NET na sua pasta pessoal, então não precisa de sudo. Defina estas duas variáveis em cada terminal novo, ou adicione-as ao ~/.zshrc:

export DOTNET_ROOT=$HOME/.dotnet
export PATH=$PATH:$DOTNET_ROOT:$DOTNET_ROOT/tools

Instale o workload maui completo, não o maui-ios. Nossa primeira execução tentou só o maui-ios. O restore falhou com NETSDK1147, porque o template também tem Android como alvo e o workload android estava faltando.

EnableCodeSigning=false permite testar um build para aparelho sem certificado. O resultado não pode ir para um celular nem para a Apple. Ele só prova que seu código compila para ios-arm64.

O que a execução mostrou

Estas linhas foram copiadas do log do job. O job inteiro levou 3 minutos e 21 segundos.

Xcode 26.6
Build version 17F113
 Workload version: 10.0.401
Successfully installed workload(s) maui.
  MauiDemo -> .../bin/Debug/net10.0-ios/iossimulator-arm64/MauiDemo.dll
Build succeeded.
Time Elapsed 00:00:23.70
  MauiDemo -> .../bin/Release/net10.0-ios/ios-arm64/MauiDemo.dll
Build succeeded.
Time Elapsed 00:02:06.70
  Created the package: bin/Release/net10.0-ios/ios-arm64/publish//MauiDemo.ipa
 97M	bin/Debug/net10.0-ios/iossimulator-arm64/MauiDemo.app
 16M	bin/Release/net10.0-ios/ios-arm64/publish/MauiDemo.ipa

O build para o simulador levou 24 segundos. O build para aparelho levou pouco mais de 2 minutos, porque um build de Release compila antecipadamente para arm64.

Combine o workload com o Xcode

Cada versão do .NET para iOS precisa de uma versão exata do Xcode. As notas de versão no GitHub, em dotnet/macios, dizem qual é. Em 19 de outubro de 2026, estes são os workload sets do .NET 10:

  • 10.0.402.1 (iOS 27.1.10018) precisa do Xcode 27.1. Saiu em 19 de outubro de 2026, com o .NET SDK 10.0.402.
  • 10.0.402 (iOS 27.0.10722) precisa do Xcode 27.0.
  • 10.0.401 (iOS 26.5.10318) precisa do Xcode 26.6. Esta é a combinação que rodamos.

Também rodamos a combinação errada de propósito. Com o workload set 10.0.402.1 e o Xcode 26.6 selecionado, o build parou com este erro:

error : This version of .NET for iOS (27.1.10018) requires Xcode 27.1.
The current version of Xcode is 26.6. Either install Xcode 27.1, or use
a different version of .NET for iOS.

Para o Xcode 27.1, o padrão nos nossos Macs, as notas de versão dão esta combinação. Não conseguimos rodá-la, porque a imagem macos-26 do GitHub não tem Xcode 27.

bash dotnet-install.sh --version 10.0.402 --install-dir "$HOME/.dotnet"
dotnet workload install maui --version 10.0.402.1

A outra solução da Microsoft é manter vários Xcodes e alternar entre eles. Veja qual está ativo, liste os instalados e escolha um:

xcode-select -p
ls -d /Applications/Xcode*.app
sudo xcode-select -s /Applications/Xcode.app
xcodebuild -version

Em um Mac da MacRun, /Applications/Xcode.app é o Xcode 26.6 e /Applications/Xcode-27.1.app é o Xcode 27.1, o padrão. Em outro Mac, use o nome exato do app que o ls mostrar. Você também pode definir DEVELOPER_DIR para uma única sessão de terminal. A Microsoft também avisa sobre uma mudança incompatível no Xcode 27. Apps iOS precisam adotar o ciclo de vida UIScene, ou travam ao abrir.

Rode, assine e publique no Mac

Para abrir o app no Simulador, o guia de CLI da Microsoft usa o target Run. Você acompanha o Simulador pela tela do Mac, a partir do Windows por VNC.

dotnet build -t:Run -f net10.0-ios

Para a App Store, adicione sua identidade de assinatura e seu perfil. Este é o exemplo da Microsoft com net8.0 trocado por net10.0. Não conseguimos rodá-lo, porque nosso teste não tinha certificado.

dotnet publish -f net10.0-ios -c Release -p:ArchiveOnBuild=true \
  -p:RuntimeIdentifier=ios-arm64 \
  -p:CodesignKey="Apple Distribution: John Smith (AY2GDE9QM7)" \
  -p:CodesignProvision="MyMauiApp"

O .ipa fica em bin/Release/net10.0-ios/ios-arm64/publish. A Microsoft indica o Transporter para o upload. Nosso guia para publicar sem Mac explica as chaves de API e o TestFlight.

Pair to Mac a partir do Visual Studio: o que a documentação exige

Talvez você prefira ficar no Visual Studio no Windows. Nesse caso, o Pair to Mac precisa do seguinte, segundo a documentação da Microsoft:

  • Remote Login ligado nos ajustes de Compartilhamento do Mac, com acesso total ao disco para usuários remotos.
  • Xcode instalado e aberto uma vez. O Pair to Mac não consegue instalar o Xcode.
  • Mono instalado, e Rosetta em um Mac com Apple silicon.
  • Um Mac que o Windows consiga alcançar. Se ele não aparecer na lista, use Add Mac e digite o endereço.

O Visual Studio então instala o .NET no Mac por SSH. Em um Mac da MacRun, o endereço seria o endereço Tailscale dele. Não testamos o Pair to Mac pelo Tailscale, então considere isso não testado. O caminho com dotnet acima é o que rodamos.

Quem não deve alugar um Mac para isso

  • Só build. O fluxo acima roda no GitHub do jeito que está. Repositórios públicos não pagam nada pelos runners padrão. Os privados pagam $0.062 por minuto de macOS, segundo a página de cobrança do GitHub. Nosso job de 3 minutos e 21 segundos é cobrado como 4 minutos, cerca de 25 centavos de dólar.
  • Depurar no seu próprio iPhone. O Hot Restart do Visual Studio 2022 instala builds de Debug em um iPhone via USB sem Mac. Ele não tem suporte no Visual Studio 2026.
  • Trabalho diário com iOS. Se você precisa do Mac todo dia, comprar um pode sair mais barato em um ano.

Quando um Mac alugado faz sentido

Um job de CI não mostra o app para você. Um Mac alugado dá o Simulador, o depurador e uma configuração de assinatura que você pode corrigir na mão. Um passe diário da MacRun é um Mac mini M6 dedicado por $15, e uma semana custa $59. O Xcode 27.1 é o padrão e o Xcode 26.6 também está instalado. O .NET não vem pré-instalado. Você instala com os comandos acima. A instalação do workload levou 34 segundos no nosso teste.

O Mac é apagado quando o passe termina. Envie seu código e copie seu .ipa antes disso. Veja Xcode a partir do Windows para configurar a tela remota.

Perguntas frequentes

Posso fazer o build de um app .NET MAUI para iOS no Windows sem Mac?

+

Não um build completo. A documentação da Microsoft diz que as ferramentas de build do iOS só rodam em um Mac. O Visual Studio envia o build para um Mac pelo Pair to Mac, ou você faz o build direto no Mac com dotnet.

Qual Xcode o MAUI do .NET 10 precisa?

+

Depende do workload set. Em 19 de outubro de 2026, o workload set 10.0.402.1 precisa do Xcode 27.1, e o 10.0.401 precisa do Xcode 26.6. As notas de versão do dotnet/macios dizem qual Xcode cada versão usa.

Por que meu build MAUI diz que precisa de outro Xcode?

+

Seu workload e o Xcode selecionado não combinam. Troque o Xcode com sudo xcode-select -s, ou instale o workload set que combina com o seu Xcode com dotnet workload install maui --version.

O Visual Studio for Mac ainda existe?

+

Não. A Microsoft aposentou o Visual Studio for Mac em 31 de agosto de 2024. Em um Mac, use a linha de comando dotnet ou o VS Code com o C# Dev Kit.

O Pair to Mac funciona com um Mac na nuvem?

+

A exigência da Microsoft é um Mac que o Windows consiga alcançar, com Remote Login ligado. Não testamos o Pair to Mac pelo Tailscale. Fazer o build com dotnet no terminal do Mac é o caminho que testamos.

Posso fazer o build de um app MAUI para iOS sem assinatura?

+

Sim. No nosso teste, dotnet build com -r ios-arm64 e -p:EnableCodeSigning=false gerou um app para aparelho sem certificado. Ele não pode ser instalado nem enviado até você assiná-lo.

Guias relacionados