Gerando artefatos .ipa com GitHub Actions

Michel Lütz
6 min readNov 6, 2022

--

Em algum momento em sua jornada como pessoa desenvolvedora Swift você irá precisar gerar um .ipa para seu projeto e disponibilizar ele para o time de Read Team, para enviar para o cliente reassinar ou para outro objetivo qualquer que necessite transportar o arquivo .ipa para algum local ou para alguém baixar. Este post vai lhe ajudar a fazer isso de uma forma segura e utilizando automação para tal finalidade.

Vamos lá!

Vamos utilizar um repositório no GitHub e o recurso de automação de workflow GitHub Actions.

No final do post vou deixar links de referências bibliográficas que usei para escrever este post.

Quem programa para a plataforma da Apple sabe que é sempre uma dor de cabeça lidar com os Certificados e Profiles, neste post vou mostra uma forma que o GitHub tem para usar eles de forma mais simplificada sem precisar gerar novos(caso você não queira).

Criando secrets para seu certificado e perfil de provisionamento

O processo de assinatura envolve armazenar certificados e perfis de provisionamento, transferi-los para o runner, importá-los para o controle de secrets do runner e usá-los em seu build.

Para usar seu certificado e perfil de provisionamento em um runner, é altamente recomendável usar secrets do GitHub. Para obter mais informações sobre como criar secrets e usá-los em um workflow, clique aqui. Nas orientações abaixo vou considerar que você sabe onde armazenar a secrets no seu repositório do GitHub.

Para resumir os secrest ficam dentro de uma url neste padrão: https://github.com/meu_usuario/meu_repo/settings/secrets/actions

Gerando secret de seu certificado de assinatura da Apple.

Este é o seu arquivo de certificado p12. Para obter mais informações sobre como exportar seu certificado de assinatura do Xcode, clique aqui.

Você deve converter seu certificado para Base64 ao salvá-lo como secret. Neste exemplo, o secret no GitHub é denominado BUILD_CERTIFICATE_BASE64.

Use o seguinte comando para converter seu certificado em Base64 e copiá-lo para a área de transferência:

base64 -i distribuition_certificate.p12 | pbcopy

OBS: Executei este comando dentro da pasta de onde armazenei meus certificados.

Com o comando executado a string de base64 já está na sua área de transferência e pode ser colada em um novo secrets no GitHub

Quando você exportou o certificado de assinatura você precisou colocar uma senha precisamos colocar esta senha em um secret do GitHub também. Neste exemplo vou criar uma entrada P12_PASSWORD.

Gerando secret para seu Profile

A documentação do GitHub indica um link que explica como fazer o download manual via Xcode. Mas fiz de outra forma que considerei mais simples. Acesse sua conta de desenvolvedor: https://developer.apple.com/account/. E Na sessão de Certificates, Identifiers & Profiles acesse o menu Profiles

Acesse o menu Profiles desta página que abriu e você terá a lista de profiles disponíveis na sua conta. Escolha o Profile de AppStore e faça o Download.

OBS: Você pode usar profile de Ad-Hoc ou enterprise também, desde que ele possa exportar o .ipa

Com o profile em sua maquina vamos fazer o mesmo procedimento de executar o comando base64 só que desta vez no arquivo .mobileprovision que você fez download no passo acima. Neste caso será denominado BUILD_PROVISION_PROFILE_BASE64

base64 -i MeuAppBacanaAppStoreDistribuition.mobileprovision | pbcopy

O ultimo secret

Um novo KEYCHAIN será criado no runner, então a senha para o novo chaveiro pode ser qualquer nova string aleatória. Neste exemplo, o segredo é denominado KEYCHAIN_PASSWORD.

Com isso concluímos nosso passos para criação dos secrets.

Criando steps no workflow

Aqui é meio que uma receita de bolo até a parte — name: Build app você pode sempre considerar copiar, após isso adicione o trecho de steps para realizar os demais passos que você quer considerar:

name: App build
on: push
jobs:
build_with_signing:
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install the Apple certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# apply provisioning profile
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
- name: Build app
...

Por motivos de indentação e para posterior consulta deixei o arquivo final em um Gist para que você possa entender melhor.

IMPORTANTE: Você vai se deparar com um comando que tem esta propriedade:

-exportOptionsPlist ./distribution-files/production-ci.plist

Neste caso na raiz do meu projeto criei uma pasta distribution-files

E dentro desta pasta um arquivo production-ci.plist com o seguinte conteúdo

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict>   <key>compileBitcode</key>   <false/>   <key>method</key>   <string>app-store</string>   <key>provisioningProfiles</key>   <dict>      <key>br.com.meubundleid</key>      <string>MeuAppBacanaAppStoreDistribuition</string>   </dict></dict></plist>

Um detalhe para a string MeuAppBacanaAppStoreDistribuition. Ela deve ser igual ao nome arquivo do profile que você enviou no secrets dos passos anteriores, neste tutorial geramos o base64 do profile: MeuAppBacanaAppStoreDistribuition.mobileprovision lembra?

Feito, configurações realizadas, não esqueça de editar seu yml do workflow para que se adeque a seu processo de geração de artefatos. Escolhendo branch, tags … Ao final vocês terá o artefato no workflow executado. Como na imagem abaixo.

OBS: neste Script eu deixei o artefato com validade de 1 dia você pode editar isso na propriedade retention-days: 1 no yml

Até a próxima

Glossário:

Runner: Executor de scripts, é uma maquina Linux, macOS ou Windows que executa os comandos do workflow. Você pode transformar sua maquina em um Runner também saiba mais aqui.

Bibliografia:

Export signing certificates and provisioning profiles: https://help.apple.com/xcode/mac/current/#/dev8a2822e0b

Download manual provisioning profiles: https://help.apple.com/xcode/mac/current/#/deva899b4fe5

Apoie o meu trabalho

Se gosta do meu conteúdo, você pode demonstrar o seu apoio com uma contribuição e me ajudar produzir ainda mais.

https://mepagaumcafe.com.br/micheltlutz/

--

--

Michel Lütz
Michel Lütz

Written by Michel Lütz

Gerente de Engenharia com MBA em Data Science for Business e BI, Mkt Digital e Data-Driven Strategy pela PUCRS.