Pipeline CI React Native (Expo) com GitHub Actions e EAS: builds automáticas e distribuição interna para testers — passo a passo
Apps mobile · Por Kevin Marcondes · Publicado em · 9 min de leitura
Pipeline CI React Native (Expo) com GitHub Actions e EAS: builds automáticas e distribuição interna para testers. Neste tutorial, você vai configurar perfis no eas.json, secrets e um workflow YAML que dispara builds preview e, na main, submete para Play (internal track) e TestFlight. No fim, validamos o fluxo e cobrimos erros comuns.
O que vamos construir: visão geral do pipeline
A ideia é que a cada PR ou push para a branch principal aconteçam builds automatizadas no EAS (Expo Application Services). Em PRs, geramos builds internas (preview) para validação rápida. Em merges na main, além dos builds, faremos a submissão automática para canais internos: Internal track no Google Play e TestFlight no iOS.
O EAS executa o build remoto; o GitHub Actions orquestra. Isso mantém runners leves, com foco em testes, lint e versionamento. O resultado: links ou disponibilização direta aos testers, reduzindo atrito entre código e validação.
Fluxo resumido:
- PR aberto: dispara build interno (Android e iOS) no EAS para testes rápidos.
- Merge na main: dispara build interno e submete para Play (internal track) e TestFlight.
- Testers recebem o app pelos meios oficiais ou via link interno (quando aplicável).
Pré-requisitos e organização do projeto
Antes de começar, garanta que o projeto e as contas estejam alinhados. Você precisará de acessos válidos às lojas e ao EAS. Não utilize credenciais pessoais fora de ambientes seguros.
Organize-se com os itens abaixo:
- Repositório no GitHub com seu app Expo (SDK compatível com EAS).
- Conta Expo com EAS habilitado e o projeto vinculado.
- Identificadores configurados: android.package e ios.bundleIdentifier no app.json/app.config.js.
- Acesso ao Google Play Console (permissões para integração de API).
- Acesso ao App Store Connect (chave de API ativa para submissão).
- GitHub Actions habilitado no repositório.
Defina perfis de build e canais no eas.json
Usaremos três perfis: development (para dev client), preview (distribuição interna para QA) e production (lojas). O preview será nosso foco para testers. Configure também os canais (channels) para organizar updates/lançamentos.
No Android, é comum usar AAB para submissão e, opcionalmente, APK para instalação direta entre testers técnicos. No iOS, a via típica de distribuição interna é o TestFlight.
{
"cli": { "version": ">= 3.13.0" },
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"channel": "development",
"ios": { "simulator": false },
"android": { "buildType": "apk" }
},
"preview": {
"distribution": "internal",
"channel": "preview"
},
"production": {
"channel": "production"
}
},
"submit": {
"internal": {
"android": { "track": "internal" },
"ios": { "ascAppId": "SEU_APP_ID_ASC" }
},
"production": {
"android": { "track": "production" }
}
}
}
Secrets no GitHub e permissões nas lojas
Crie secrets no GitHub para o workflow. Nunca versione chaves privadas, JSONs de serviço ou tokens. Use apenas GitHub Secrets e restrinja o acesso (environments protegidos).
Principais secrets:
- EXPO_TOKEN: token de acesso de conta Expo/EAS para builds não interativos.
- GOOGLE_SERVICE_ACCOUNT_KEY: JSON da conta de serviço do Google Play (com permissão para subir ao track interno).
- ASC_ISSUER_ID, ASC_KEY_ID, ASC_PRIVATE_KEY: credenciais de API do App Store Connect para submissão ao TestFlight.
- Variáveis de build do app (se houver): mantenha-as como secrets e injete-as em tempo de build.
Workflow do GitHub Actions: build e distribuição interna
O YAML abaixo orquestra o fluxo: instala dependências, roda testes, autentica no EAS e dispara builds preview para Android e iOS. Em pushes na main, submete para Play (internal track) e TestFlight.
Se quiser entender a base dos gatilhos e boas práticas de Actions, veja este guia sobre pipeline automático: como configurar pipeline de deploy automático. Atenção: o job roda em runners GitHub hospedados; o build acontece remotamente no EAS.
name: ci-expo-eas
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-and-distribute:
runs-on: ubuntu-latest
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
EXPO_APPLE_APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
EXPO_APPLE_APP_STORE_CONNECT_KEY_ID: ${{ secrets.ASC_KEY_ID }}
EXPO_APPLE_APP_STORE_CONNECT_PRIVATE_KEY: ${{ secrets.ASC_PRIVATE_KEY }}
GOOGLE_SERVICE_ACCOUNT_KEY: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn'
- name: Install deps
run: yarn install --frozen-lockfile
- name: Run tests (optional)
run: yarn test --if-present
- name: Install EAS CLI
run: npm i -g eas-cli
- name: Build preview (Android + iOS)
run: eas build --platform all --profile preview --non-interactive
- name: Submit to Google Play (internal track)
if: github.ref == 'refs/heads/main'
run: eas submit -p android --profile internal --non-interactive
- name: Submit to TestFlight
if: github.ref == 'refs/heads/main'
run: eas submit -p ios --profile internal --non-interactive
- name: List latest builds
run: eas build:list --limit 5
Distribuição para testers: opções e quando usar
Com os builds publicados, escolha a via de distribuição interna adequada. Para Android, o internal track do Play escala bem para times de QA. Para iOS, o TestFlight é o fluxo padrão para testes internos/externos. Em times técnicos, APK interno (preview) pode ser útil para validação rápida.
Para detalhes Android-only de pipeline CI e assinatura, consulte: pipeline CI para Android com GitHub Actions. Para publicações formais, veja também: como publicar app Android e como publicar app iOS.
| Plataforma | Perfil | Objetivo | Artefato | Distribuição |
|---|---|---|---|---|
| Android | preview | QA interno rápido | AAB (padrão) ou APK (opcional) | Link EAS ou Google Play (internal track) |
| iOS | preview | QA interno | IPA | TestFlight (grupos internos ou externos) |
| Android/iOS | development | Dev client para features em construção | APK/IPA dev client | Instalação interna via link/QR do EAS |
| Android/iOS | production | Release público | AAB/IPA | Lojas (tracks estáveis) |
Como confirmar que funcionou
Depois do workflow, valide se os builds foram criados e se a submissão progrediu. Não compartilhe links de build fora do grupo autorizado de testers. Em caso de erros de permissão, revise as credenciais e papéis nas lojas.
- Confirme no painel do EAS que os jobs concluíram com sucesso.
- Verifique no Google Play Console se o artefato chegou ao internal track.
- No App Store Connect, confira o processamento do build e a disponibilidade no TestFlight.
- Teste a instalação em um dispositivo real (um Android e um iOS).
# Listar builds recentes e seus estados
npx eas-cli build:list --limit 10 --json
# Status de submissões
npx eas-cli submit:status --platform android
npx eas-cli submit:status --platform ios
Solução de problemas comuns
Erros recorrentes nesse fluxo costumam estar ligados a autenticação, identificadores do app e permissões nas lojas. Abaixo, alguns sintomas e caminhos práticos de correção.
- Autenticação falhou (You are not authenticated): verifique EXPO_TOKEN e se o token tem acesso ao projeto.
- Android rejeitado pelo Play (permission denied): confira se a conta de serviço tem permissão para gerenciar artefatos e o aplicativo correto.
- Bundle/package ausente: defina android.package e ios.bundleIdentifier no app.json/app.config.js.
- iOS: chave inválida no App Store Connect: confira issuer ID, key ID e o conteúdo da chave privada.
- Build interno iOS não instala fora do TestFlight: restrições de assinatura; use TestFlight para testers.
- Mudanças nativas não refletidas: limpe pastas nativas geradas e rode o build novamente quando alterar configurações críticas.
Segurança e boas práticas no CI/CD mobile
Proteja credenciais e reduza a superfície de ataque. Em projetos sensíveis, adote environments protegidos, revisão em dupla para secrets e logs sem vazamento de dados. Veja também este checklist dedicado: Checklist de segurança CI/CD.
Se o volume de jobs crescer, vale estudar auto-escalonamento de runners self-hosted para etapas de testes pesados (não para builds EAS em si): auto-escalar runners no GitHub Actions.
- Secrets somente via GitHub Environments com aprovação.
- Rotacione chaves periodicamente e desative as não usadas.
- Evite imprimir variáveis sensíveis em logs.
- Restrinja quem pode disparar workflows na branch principal.
Perguntas frequentes
O EAS compila no meu runner do GitHub Actions?
Não. O GitHub Actions só orquestra. O build roda nos servidores do EAS. O runner precisa apenas do Node, do EAS CLI e das credenciais para iniciar os jobs remotos e, quando for o caso, submeter aos stores.
Consigo distribuir Android sem passar pelo Google Play?
Sim, gerando APK em um perfil interno (preview) e compartilhando o link do build do EAS. Para fluxo de QA mais escalável e com controle de grupos, prefira o internal track do Play Console.
Como versionar corretamente entre builds internos e produção?
Mantenha version, android.versionCode e ios.buildNumber consistentes no app config. Você pode automatizar incremento com scripts de CI, garantindo que builds internos não conflitem com produção.
Posso rodar testes E2E (Detox) nesse pipeline?
Sim, mas execute-os antes de acionar o EAS Build, em jobs separados, usando simuladores/emuladores nos runners. O build EAS deve ser disparado apenas após a suíte passar com sucesso.
Quais variáveis de ambiente do app devo expor no CI?
Apenas o mínimo necessário. Use secrets do GitHub e, quando aplicável, variáveis seguras no EAS. Evite commitar .env. Configure leitura por variáveis de ambiente em tempo de build.
Preciso de conta paga nas lojas para TestFlight e internal track?
Você precisa de contas válidas e permissões adequadas no App Store Connect e no Google Play Console. Políticas e requisitos podem mudar; verifique no painel de cada loja antes de configurar o pipeline.
Quer adaptar este pipeline ao seu app?
Se precisa ajustar profiles, versionamento ou segurança do fluxo, entre em contato para discutir o seu cenário.
Falar sobre CI/CD mobileVeja também
- tutorial: configurar mTLS entre Traefik e serviços em Docker Compose usando smallstep CA e certificados automáticos — passo a passo
- Tutorial: integrar Sentry ao pipeline de deploy com GitHub Actions para upload automático de source maps e criação de issues (PHP e JavaScript) — passo a passo
- Configurar retenção e compactação de logs de containers Docker com journald + logrotate + rsyslog em VPS com pouco disco
- tutorial: configurar GitHub Actions para testes de integração com PostgreSQL em containers efêmeros e rollback automático de migrações — guia prático