2 pontos por GN⁺ 4 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • Depois de concluir a configuração inicial da conta Apple e dos certificados, é possível automatizar a compilação, assinatura e distribuição de apps para Mac e iOS usando apenas as ferramentas de CLI dentro do Xcode.app
  • Em project.yml, o XcodeGen recria o .xcodeproj, e xcodebuild, notarytool, stapler e devicectl cuidam de tudo, da geração do projeto à notarização no Mac e à instalação no iPhone
  • A distribuição para Mac pode ser executada em ordem com apenas scripts/release.sh: arquivamento, assinatura com Developer ID, notarização, anexação do ticket, validação no Gatekeeper e instalação em /Applications, interrompendo imediatamente em caso de falha
  • Para compilação e testes rápidos, é possível usar CODE_SIGNING_ALLOWED=NO, mas esse build com assinatura temporária não passa pelo Gatekeeper e também não vincula permissões como iCloud KVS e App Group ao Team ID real
  • Se a chave privada de assinatura e a senha de notarização forem guardadas no keychain de login, e os comandos e regras de distribuição forem registrados em CLAUDE.md ou AGENTS.md, agentes como o Claude Code podem repetir todo o fluxo de trabalho

O que dá para fazer sem a interface do Xcode

  • O próprio Xcode precisa estar instalado, mas não precisa ser aberto; xcodebuild, notarytool, stapler e devicectl são todos ferramentas de shell dentro do Xcode.app e podem ser executadas de forma independente
  • A configuração inicial, como login com Apple ID, criação do certificado Developer ID e armazenamento da senha de notarização, exige GUI ou terminal interativo
  • Depois da configuração inicial, é possível fazer sem usar o mouse: geração do projeto, build, archive, exportação do app assinado, notarização, validação, instalação e até distribuição para um iPhone real
  • Se travar na configuração ou na escrita de scripts, é possível fornecer os requisitos da tarefa e os valores específicos do projeto ao Claude Code ou a outra ferramenta de programação com LLM para montar o workflow

Selecionar toda a cadeia de ferramentas do Xcode

  • Primeiro, é preciso verificar se o resultado de xcode-select -p é /Applications/Xcode.app/Contents/Developer
  • Se as Command Line Tools independentes estiverem selecionadas, defina a cadeia completa de ferramentas do Xcode com o comando abaixo
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
  • O /Library/Developer/CommandLineTools instalado com xcode-select --install inclui clang e git, mas não traz todo o conjunto de ferramentas para desenvolvimento de apps, como iOS SDK, notarytool e devicectl
  • Se o Xcode já estiver instalado, o pacote separado de Command Line Tools não é necessário
  • A aceitação da licença e a instalação de componentes adicionais também podem ser feitas pela CLI
sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch

Reproduzir o projeto com XcodeGen

  • O XcodeGen gerencia as configurações do projeto Xcode em YAML e recria o .xcodeproj a cada build
  • É possível baixá-lo no GitHub ou instalar via Homebrew
brew install xcodegen
  • O .xcodeproj é uma pasta que no macOS aparece como se fosse um arquivo, e como o Xcode muda constantemente seus arquivos internos e referências, isso pode gerar conflitos ou mudanças desnecessárias no repositório Git
  • Ao versionar apenas o project.yml e ignorar o .xcodeproj gerado, a configuração do projeto permanece reproduzível
xcodegen generate

Configuração da conta Apple Developer e dos certificados

  • É preciso adicionar o Apple ID em Settings → Accounts do Xcode
  • Para distribuir o app e fazer a notarização, é necessária uma conta paga do Apple Developer
  • O certificado de distribuição é criado em Settings → Accounts → Apple ID → Manage Certificates… → + → Developer ID Application
  • Apple Development e Developer ID Application têm finalidades diferentes
    • Apple Development é usado para rodar no próprio dispositivo ou transferir para o iPhone durante depuração local
    • Developer ID Application é necessário para distribuir um .app notarizado que passe pelo Gatekeeper também em Macs de outras pessoas
  • Quando o certificado Developer ID Application é criado, o certificado e sua chave privada correspondente são instalados no keychain de login
  • A chave privada é usada na assinatura real e não pode ser baixada novamente; por isso, não a exclua e faça backup do keychain

Armazenar credenciais de notarização no keychain

  • A notarização de apps para Mac é o processo de enviar o app assinado à Apple para inspeção de malware
  • O notarytool autentica com um perfil armazenado no keychain, e na criação inicial do perfil é preciso digitar interativamente uma senha específica de app
xcrun notarytool store-credentials App-Name \
  --apple-id "you@example.com" \
  --team-id YOUR-TEAM-ID
  • Em vez de reaproveitar o perfil de notarização de outro app, o ideal é criar um perfil com o nome do app, evitando falhas silenciosas em outros ambientes
  • A senha específica de app é diferente da senha do Apple ID e pode ser criada em Apple ID site, em Sign-In & Security → App-Specific Passwords
  • Se a senha do Apple ID for alterada, a senha específica de app pode expirar sem aviso separado
    • Se aparecer 401 invalid credentials durante a notarização, antes de suspeitar de toda a configuração, vale verificar se a senha específica de app expirou
  • É possível validar se o perfil foi salvo com o comando abaixo
xcrun notarytool history --keychain-profile App-Name
  • Se a senha específica de app ficar guardada em um cofre do 1Password acessível ao Claude Code, também dá para delegar ao agente a criação do perfil de notarização de um novo app
  • Também é possível automatizar a entrada da senha com --password, mas como isso pode deixar a senha no histórico do shell, o recomendado é digitá-la manualmente uma vez e depois armazená-la no keychain ou no 1Password

Configuração local de assinatura e separação de segredos

  • O Team ID real e o prefixo do bundle necessários para a assinatura são armazenados em Local.xcconfig
cp Local.xcconfig.example Local.xcconfig
BUNDLE_PREFIX     = your.real.prefix
DEVELOPMENT_TEAM  = YOUR-TEAM-ID
  • Adicione Local.xcconfig ao .gitignore para que as configurações locais de cada projeto não entrem no repositório
  • Como a chave privada de assinatura fica no keychain de login e a senha específica de app para notarização fica no perfil do keychain do notarytool, informações sensíveis não ficam registradas no Git

Automatizar a distribuição para Mac com release.sh

  • O scripts/release.sh do repositório executa todo o pipeline de distribuição do app para Mac com um único comando
./scripts/release.sh
  • O script funciona na seguinte ordem

    1. Verifica previamente se xcodegen e o perfil de notarização existem
    2. Recria o projeto com xcodegen generate
    3. Gera um archive Release com xcodebuild archive
    4. Exporta o app assinado com Developer ID usando ExportOptions.plist e xcodebuild -exportArchive
    5. Compacta o app em ZIP e envia à Apple com notarytool submit --wait
    6. Anexa o ticket de notarização com stapler staple
    7. Valida se o Gatekeeper permite a execução com spctl
    8. Encerra processos existentes e copia o app para /Applications
    9. Registra o app instalado com lsregister
    10. Revalida o ticket e o status no Gatekeeper do bundle instalado
  • Mesmo que o modelo conheça o procedimento geral de distribuição, informações específicas do projeto como nome do scheme, Team ID, nome do perfil de notarização e local de instalação precisam ser fornecidas pelo usuário

  • Se o primeiro script falhar, será necessário ajustá-lo iterativamente com base na saída da execução, mas depois que o workflow estiver estável, basta executar o comando de distribuição sem mudanças adicionais

  • Evitar falhas e distribuições incompletas

    • set -euo pipefail faz o script parar imediatamente se qualquer comando falhar, evitando que um estado incompleto seja tratado como sucesso
    • cd "$(dirname "$0")/.." faz o script ir para a raiz do repositório independentemente do diretório de onde foi chamado
    • O bloco de pré-verificação valida xcodegen e o perfil de notarização antes do archive, que leva mais tempo
    • Não só o app exportado, mas também o app copiado para /Applications, é verificado novamente para detectar casos em que o bundle se corrompe durante a cópia
    • Se outro perfil de notarização for necessário, ele pode ser sobrescrito por variável de ambiente
    TZED_NOTARY_PROFILE=<name> ./scripts/release.sh
    

Passar regras de distribuição para o agente

  • Se o release.sh faz a distribuição com um único comando, então CLAUDE.md ou AGENTS.md permite que o agente use esse comando em todas as sessões sem precisar de instruções adicionais
  • O documento deve registrar a recriação do projeto, os testes unitários, o build rápido no macOS e o comando de distribuição real
xcodegen generate
swift test

xcodebuild -project YOUR-APP-NAME.xcodeproj \
  -scheme YOUR-APP-NAME-macOS \
  -destination 'platform=macOS' \
  CODE_SIGNING_ALLOWED=NO build

./scripts/release.sh
  • A diferença entre os dois caminhos de build também precisa estar documentada
    • O build com CODE_SIGNING_ALLOWED=NO é adequado para CI e verificações locais rápidas
    • Para distribuir de verdade um app de barra de menu, passar por atributos de quarentena e usar sincronização via iCloud, é necessário o release.sh, que faz assinatura com Developer ID e notarização
  • Se você instruir que o método usado em um app sirva como referência para outros repositórios, o Claude Code poderá replicar a mesma configuração em apps futuros

Build rápido sem assinatura e testes

  • Testes unitários baseados em Swift Package Manager são executados sem build via Xcode
swift test
  • Uma verificação rápida de compilação de app macOS pode ser feita com a assinatura desativada
xcodebuild -project TZed.xcodeproj \
  -scheme TZed-macOS \
  -destination 'platform=macOS' \
  CODE_SIGNING_ALLOWED=NO build
  • O build para simulador de um app iOS e de extensões de widget também pode ser executado da mesma forma
xcodebuild -project TZed.xcodeproj \
  -scheme TZed-iOS \
  -destination 'generic/platform=iOS Simulator' \
  CODE_SIGNING_ALLOWED=NO build
  • O build com assinatura temporária criado com CODE_SIGNING_ALLOWED=NO pode ser usado para compilar e rodar no simulador
  • Esse build é rejeitado pelo Gatekeeper e, como não tem prefixo de equipe, permissões como iCloud KVS e App Group não se vinculam corretamente, então ele não serve para distribuição

Distribuição headless para iPhone real

  • A distribuição para dispositivos iOS não tem a etapa de notarização dos apps para Mac e usa xcodebuild e devicectl
  • Apps para dispositivo real são compilados e assinados com certificado Apple Development e perfil de provisionamento de desenvolvimento
xcodebuild -project TZed.xcodeproj \
  -scheme TZed-iOS \
  -destination 'generic/platform=iOS' \
  -allowProvisioningUpdates \
  -derivedDataPath build/ios \
  archive -archivePath build/TZed-iOS.xcarchive
  • O .app gerado é instalado especificando o UDID do dispositivo conectado
xcrun devicectl device install app \
  --device <DEVICE-UDID> build/ios/…/TZed.app
  • devicectl list devices mostra os dispositivos conectados e emparelhados, junto com seus UDIDs
  • Ao usar -allowProvisioningUpdates, os perfis de provisionamento de desenvolvimento necessários são buscados automaticamente

Como a assinatura de código funciona sem GUI

  • Ao criar um certificado Developer ID Application, a Apple emite o certificado e o Mac gera a chave privada correspondente, armazenando ambos no keychain de login

  • O codesign chamado por xcodebuild assina o binário com a chave privada e inclui no app o certificado que leva até a autoridade raiz da Apple, para que seja possível validar quem assinou

  • Ao usar signingStyle: automatic, o xcodebuild escolhe o certificado correspondente ao Team ID e busca na Apple os perfis de provisionamento necessários

  • Por isso, não é necessário versionar perfis de provisionamento no repositório

  • Permissões, notarização e stapling

    • O arquivo .entitlements de cada target contém permissões como sandbox, cliente de rede, iCloud KVS e App Group
    • Como as permissões são vinculadas no momento da assinatura com o Team ID real, builds com assinatura temporária não fazem iCloud e App Group funcionarem corretamente
    • Assinatura e notarização são etapas diferentes
    • A assinatura prova quem criou o app
    • A notarização é o processo em que a Apple analisa o app assinado em busca de malware e emite um ticket
    • O stapling anexa esse ticket ao app para que o Gatekeeper confie nele mesmo offline
    • Em apps LSUIElement de barra de menu que usam UI oculta, a notarização é necessária para evitar detecção pelo XProtect
  • Comandos de validação manual

    codesign -dv --verbose=4 /Applications/TZed.app
    spctl -a -vvv -t exec /Applications/TZed.app
    stapler validate /Applications/TZed.app
    
    • codesign verifica o signatário e o certificado
    • spctl verifica se o Gatekeeper permitirá a execução
    • stapler validate valida se o ticket de notarização foi anexado

Ferramentas padrão executadas pelo agente

  • Não é necessário um servidor MCP separado para build nem plugins dedicados; o Claude Code executa CLIs padrão em um shell não interativo
  • As ferramentas usadas são xcodebuild, xcrun notarytool, xcrun stapler, spctl, codesign, devicectl, xcodegen e swift
  • O CLAUDE.md transmite ao agente a convenção de nomes do perfil de notarização, a diferença entre build rápido e distribuição real, e a regra de usar release.sh na hora da distribuição
  • Apenas o notarytool store-credentials inicial permanece como etapa interativa; todo o restante pode ser automatizado

Substituir tarefas da GUI do Xcode pela CLI

  • A geração do .xcodeproj gerenciado pelo Xcode é substituída por project.yml e xcodegen generate
  • ⌘B ou o botão Run correspondem a xcodebuild … build
  • Product → Archive é tratado com xcodebuild … archive
  • A distribuição de app pelo Organizer pode ser substituída por xcodebuild -exportArchive
  • O upload pelo Organizer é feito com xcrun notarytool submit --wait
  • Para anexação automática do ticket, use xcrun stapler staple
  • A instalação por arrastar e soltar em /Applications pode ser feita com cp -R e lsregister
  • A ação Run em um iPhone real é substituída por xcodebuild archive e devicectl device install
  • Depois de instalar Xcode e XcodeGen, configurar as credenciais iniciais e escrever release.sh e CLAUDE.md, novas distribuições de build podem ser executadas com uma frase ou um único comando

1 comentários

 
GN⁺ 4 시간 전
Comentários do Hacker News
  • Há muita coisa que não dá para resolver no sandbox, então eu executo agentes de IA diretamente no Mac, mas depois de ver o caso em que a xAI fez upload até do diretório home com as chaves SSH incluídas, estou repensando seriamente essa escolha
    Não me preocupo tanto se a própria máquina quebrar. Quase tudo está em backup ou commitado no Git, então dá para recuperar em poucas horas. Mas eu definitivamente não quero que o diretório .ssh seja enviado para um agente de IA, e isso não deve ser bloqueado por prompt, e sim no nível do sistema. Estou considerando criar um usuário separado e aplicar permissão 700 ao diretório home. Parece um retrocesso da segurança para os anos 1990, mas, em troca, existe a vantagem de conseguir terminar o trabalho numa velocidade sem precedentes. Eu mesmo uso esse método arriscado, então não estou tentando criticar ninguém

    • Não precisa necessariamente rodar no Mac host. Os Macs recentes suportam virtualização com perda de desempenho quase nula, então é fácil usar máquinas virtuais macOS ou Linux da mesma arquitetura para desenvolvimento
      Como solução empacotada, dá para usar o open source Tart https://tart.run/ ou VirtualBuddy https://github.com/insidegui/VirtualBuddy, ou até fazer seu próprio vibe coding com uma ferramenta que envolva a API do sistema operacional https://developer.apple.com/documentation/virtualization. Recentemente também surgiu o Apple container https://github.com/apple/container
    • Estou criando uma ferramenta wrapper para executar o Claude como um usuário separado chamado agent. Há um ano isso falhou por causa de OAuth e do keychain, mas recentemente consegui implementar com a orientação do Claude de que dá para usar CLAUDE_CODE_OAUTH_TOKEN
      Ainda é necessária uma ferramenta auxiliar para configurar permissões com ACL, mas no momento funciona no macOS. O nível de risco fica mais ou menos entre o sandbox padrão do Claude e o isolamento completo por contêiner ou máquina. Com a melhora do sandbox do próprio Claude, eu estava duvidando do custo-benefício desse projeto de defesa em camadas, mas, vendo a possibilidade de vazamento do diretório home, há motivo de sobra para continuar. Ainda não publiquei como open source, mas estou disposto a conversar com quem tiver interesse
    • Eu executo a IA em um contêiner Docker headless e deixo que ela acesse apenas o Git para contribuir só com código. Se precisar de segredos, forneço um contêiner Docker guardado no repositório; se precisar de infraestrutura, o fluxo de trabalho é fazer com que ela abra um ticket no Jira
    • Fiquei curioso sobre como é feito o processo de registrar o identificador de bundle sem abrir o Xcode
  • Estou, por diversão, compilando e testando apps iOS usando só Linux, e é surpreendentemente simples, além de https://github.com/xtool-org/xtool funcionar muito bem
    Mesmo sem precisar publicar no TestFlight ou na App Store, também dá para instalar diretamente no iPhone via USB a partir do Linux. Se você ainda não estiver convencido, pode pedir ao agente de código para criar e enviar um app iOS Hello World, e assim começar facilmente

    • Estou trabalhando do mesmo jeito, exceto pelo fato de rodar Linux no WSL do Windows. Transfiro o IPA para o celular com o Sideloadly e funciona bem
    • Depois de transferir o app por USB, é preciso manter o iPhone conectado?
    • Os agentes de código já conhecem o xtool?
  • Meu projeto open source Axiom ajuda ferramentas de execução de código a realizar com eficiência tarefas de desenvolvimento para os sistemas operacionais da Apple
    Ele inclui várias tecnologias e agentes, além de ferramentas para LLM como xclog, xcprof, xcsym e xcui. Elas expõem os recursos necessários com eficiência de tokens e também são úteis para tecnologias ou agentes fora do Axiom. Axiom: https://charleswiltgen.github.io/Axiom/, ferramentas CLI: https://charleswiltgen.github.io/Axiom/tools/

    • Será que também funciona direito em uma codebase Kotlin Multiplatform? Tem código nativo em Swift, mas eu queria entender como fica o desempenho ou o comportamento ao compartilhar parte da lógica
    • Acho que a próxima fronteira das ferramentas para apps iOS são servidores de build Linux auto-hospedáveis; queria saber sua opinião sobre isso
    • Funciona também com Flutter?
  • É uma sensação estranha ler a frase “pedi ao Claude Code para criar um script que, sem abrir o Xcode, faz archive, assinatura com Developer ID, notarização, stapling e instalação em /Applications, interrompendo claramente em qualquer etapa que falhe”. Isso porque o próprio texto que estou lendo também parece o Claude falando conosco
    Também soa estranho que, em quase todas as etapas do texto, se repita algo como pedir de novo para o LLM: “mostre este texto ao Claude Code ou à ferramenta de coding com LLM que você preferir e deixe que ela resolva”, “se não souber, pergunte ao LLM e peça ajuda na configuração”, “o objetivo de usar LLM é evitar trabalho manual indesejado”, “peça que ele crie um workflow”

    • Este texto não foi escrito pelo Claude, e sim por mim mesmo
    • Parece uma estrutura circular: mostrar ao Claude um site escrito pelo Claude e fazer o Claude montar o ambiente de build com base nisso
    • Pelos erros no texto, achei que não tivesse sido escrito por IA, mas agora já começo a pensar que talvez a IA esteja errando de propósito
  • Como alguém que desenvolve apps para Mac e iOS com agentes há mais de um ano, considero este texto um conselho ruim. Em especial, o excelente Xcode MCP exige que o Xcode esteja aberto
    Com as ferramentas MCP, é possível acessar vários recursos de forma muito mais rápida e concisa do que com xcodebuild, além de permitir a geração e renderização de #Preview, o que é impossível com o Xcode fechado. O MCP e o agente embutido do Xcode 27 também controlam muito bem o simulador via DeviceHub. O DeviceHub substitui o Simulator.app e parece permitir que o agente entenda e opere a API de acessibilidade sem precisar de gambiarras com ferramentas como axe
    O Xcode MCP não é perfeito. O problema de aparecer uma janela de permissão toda vez que o agente é executado eu contornei automatizando a aprovação com o Keyboard Maestro. Ainda assim, o Xcode 27 melhorou muito a usabilidade do vibe coding no Xcode. Agora eu executo o Codex na própria UI do agente do Xcode, sem lidar separadamente com o MCP, e esse ambiente de execução orienta melhor o modelo a usar as ferramentas disponíveis. No fim, o mais importante é obter feedback mais rápido e validação mais robusta

    • Existe o Xcode-mcp-proxy, que faz proxy do Xcode MCP, clica nos diálogos e até restaura a conexão. Fiquei curioso se você usa Peekaboo para testar apps macOS ou se usa automação comum de screenshots
    • O Xcode MCP da Sentry também vale a pena testar. É muito mais abrangente e nem exige que o Xcode fique aberto
  • Se você quiser mexer o mínimo possível nas IDEs de iOS e Android, React Native e Expo também são uma boa escolha
    Xcode e Android Studio são usados só para instalar os simuladores de dispositivo; até a publicação nas lojas, o restante é resolvido pela toolchain do Expo. Mesmo no Windows, onde não dá para instalar o Xcode, é possível rodar apps iOS diretamente no iPhone usando os apps gerenciados do Expo. Como ponto de partida com RN e Expo, o bem mantido Ignite é excelente: https://github.com/infinitered/ignite

  • Em termos estritos, isso ainda é usar o Xcode. O Xcode é basicamente uma GUI extremamente bugada que encapsula vários utilitários e apps UNIX de nível de sistema, em geral estáveis
    Lançar apps via CLI é uma prática antiga, e pelo menos desde 2012, quando publiquei meu primeiro app com Xcode, isso já era possível

    • Eu sei disso. A questão, porém, é que quem está usando o Xcode não sou eu, e sim o Claude
    • Por causa da barreira de entrada depois de abrir o Xcode, eu nem cogitava tentar criar programas para macOS
  • Pelo menos para parte da depuração, todo mundo acaba tendo que usar o Xcode
    O build o agente já consegue fazer quase todo pela linha de comando e, se você der instruções explícitas conforme a situação, ele consegue fazer isso mais rápido. Se você usar os grupos de sincronização de sistema de arquivos do Xcode, o XcodeGen pode ser trabalho extra desnecessário
    No iOS, a recomendação que eu mais faria é adicionar ao agente a funcionalidade do App Store Connect: https://github.com/rorkai/App-Store-Connect-CLI. Aí, além de não precisar deixar o Xcode sempre aberto, você nem precisa estar perto do MacBook. Dá para fazer alterações no iPhone com o Codex, mandar o asc gerar o build e subir para o TestFlight, baixar e executar a nova versão, e repetir o processo

    • Quase terminei um app iOS inteiro com um agente, e o agente cuidou até do lançamento na App Store e da divulgação nas redes sociais. Eu só usei o Xcode para conferir previamente o build no dispositivo e decidir a direção do próximo prompt
  • Continua me incomodando o fato de que desenvolvedores sem orçamento para comprar um Mac ficam, na prática, excluídos do desenvolvimento iOS. Cada vez que os produtos da Apple ficam mais caros, mais gente deixa de poder participar do desenvolvimento

    • É triste que exista gente sem acesso à tecnologia, mas hoje a Apple também oferece aparelhos baratos em comparação com concorrentes de especificações parecidas ou até inferiores. Um exemplo é o MacBook Air com Apple Silicon e memória suficiente
  • Se a ideia é fazer vibe coding de apps, no longo prazo Expo teria sido uma escolha melhor. Como é baseado em React, há muito mais código React do que Swift nos dados de treino dos LLMs, e a qualidade do código resultante também é maior
    Tudo pode ser feito pela linha de comando, e como é uma web view, depurar também é fácil. Depois de compilar como app iOS nativo, a sensação é parecida com a de outros apps nativos. Combinando Expo e Fastlane, dá para automatizar completamente o envio e a distribuição no iOS, a ponto de subir uma nova versão para a App Store com um único comando

    • Não existem etapas que não dá para automatizar, como registrar o próprio app ao criar um novo?
    • Esse Expo de que você falou é https://expo.dev/? Ao acessar agora, aparece um aviso dizendo que “o código está quebrado e ocorreu um erro que precisa ser verificado”