Tutorial: configurar pipeline CI para Android com GitHub Actions, proteger keystore e publicar rollout internal — passo a passo
Apps mobile · Por Kevin Marcondes · Publicado em · Atualizado em · 9 min de leitura
Este é o tutorial: configurar pipeline CI para Android com GitHub Actions, proteger keystore e publicar rollout internal. Você vai preparar secrets, ajustar o Gradle, escrever o workflow YAML e validar a publicação. É um guia direto para sair do zero, assinar o app com segurança e automatizar o envio à faixa de testes interna.
Pré‑requisitos
Você precisa de alguns itens preparados antes de automatizar o build e a publicação. Eles garantem que a pipeline rode sem interrupções e com segurança.
Se o seu projeto ainda não publica manualmente, revise o fluxo de assinatura e versão local antes de automatizar. Para conhecer o envio manual, veja o guia sobre a Play Store em como publicar um aplicativo Android.
- Projeto Android com plugin do Android Gradle funcionando localmente.
- Conta no Google Play Console com um app já criado (packageName definido).
- Conta de serviço no Play Console com chave JSON baixada e permissão de publicador.
- Keystore de assinatura do app (JKS ou PKCS12) e senhas associadas.
- Repositório no GitHub com GitHub Actions habilitado.
- Java 17 no build (AGP recentes exigem).
Visão geral do pipeline CI/CD
Vamos montar uma pipeline que: assina o app, gera o bundle (.aab) e publica na faixa internal. Você terá um workflow único com passos encadeados. Isso pode publicar uma versão para testers, então use branches protegidas.
Se quiser ver um pipeline de deploy genérico com Actions, confira também este pipeline de deploy automático com GitHub Actions e complemente sua leitura.
- Checkout do código e cache do Gradle.
- Instalação do Java e do Android SDK necessário.
- Restauração do keystore a partir de secrets.
- Geração do app bundle com Gradle (bundleRelease).
- Publicação automática com o Gradle Play Publisher na track internal.
- Upload do artefato como evidência do build.
Passo 1 — Configurar assinatura e Play no Gradle
Prepare seu módulo de app para ler variáveis de ambiente no signingConfig e habilite a publicação via plugin do Play. Substitua a versão do plugin pela atual e ajuste minify/proguard conforme seu projeto.
O arquivo JSON da conta de serviço será criado no workspace do Actions durante o job. Mantemos o caminho simples (service-account.json).
// app/build.gradle (Groovy DSL)
plugins {
id 'com.android.application'
id 'com.github.triplet.play' version 'x.y.z' // substitua pela versão atual
}
android {
namespace "com.seu.pacote" // ajuste para o seu package
compileSdk 34 // ajuste para seu projeto
defaultConfig {
applicationId "com.seu.pacote"
minSdk 24
targetSdk 34
versionCode 1 // incremente a cada release
versionName "1.0.0"
}
signingConfigs {
release {
storeFile file(System.getenv("ANDROID_KEYSTORE_PATH") ?: "keystore.jks")
storePassword System.getenv("ANDROID_KEYSTORE_PASSWORD")
keyAlias System.getenv("ANDROID_KEY_ALIAS")
keyPassword System.getenv("ANDROID_KEY_PASSWORD")
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
play {
// O arquivo será escrito pelo workflow na raiz do repo
serviceAccountCredentials.set(file("service-account.json"))
track.set("internal")
defaultToAppBundles.set(true) // publica .aab
// releaseStatus.set("completed") // opcional: completed/draft
}
Passo 2 — Criar conta de serviço no Play Console
Crie uma conta de serviço vinculada ao app no Play Console e gere a chave JSON. Conceda apenas as permissões necessárias para publicar na faixa internal.
Guarde o JSON com cuidado. Se vazar, revogue e gere uma nova chave imediatamente.
Anote o packageName exato do app. Ele será usado pelo plugin para localizar o aplicativo.
- Vá em Acesso à API no Play Console e vincule ao Google Cloud.
- Crie uma conta de serviço e gere a chave JSON.
- Atribua permissões de publicação ao app alvo.
- Baixe o arquivo JSON e armazene em local seguro.
Passo 3 — Adicionar secrets no GitHub com segurança
Vamos armazenar tudo como secrets. Para o keystore, use base64 para evitar problemas binários. No workflow, vamos decodificar para um arquivo .jks.
No repositório, acesse Settings > Secrets and variables > Actions e crie os seguintes secrets.
| Nome do secret | Conteúdo | Dica |
|---|---|---|
| ANDROID_KEYSTORE_BASE64 | Keystore (.jks ou .p12) em base64 | Use base64 do seu SO; evite copiar arquivos binários direto. |
| ANDROID_KEYSTORE_PASSWORD | Senha do keystore | Não reutilize senhas entre ambientes. |
| ANDROID_KEY_ALIAS | Alias da chave de assinatura | Confirme o alias com keytool se tiver dúvida. |
| ANDROID_KEY_PASSWORD | Senha do alias | Pode ser igual à do keystore, mas não é obrigatório. |
| PLAY_SERVICE_ACCOUNT_JSON | Conteúdo do JSON da conta de serviço | Cole o JSON completo; o workflow cria o arquivo. |
| PLAY_PACKAGE_NAME | Package name do app (ex.: com.seu.pacote) | Mantém o valor explícito para validações. |
Passo 4 — Workflow YAML do GitHub Actions
Abaixo está um workflow funcional. Ele instala Java 17, prepara o Android SDK, restaura o keystore, gera o .aab e publica na faixa internal. Isso executa publicação, então restrinja o gatilho conforme sua política (ex.: somente tags).
name: android-ci-internal
on:
push:
branches: [ main ]
# Para maior segurança, você pode publicar só em tags:
# tags: [ 'v*' ]
jobs:
build-and-publish:
runs-on: ubuntu-latest
env:
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
PLAY_SERVICE_ACCOUNT_JSON: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
PLAY_PACKAGE_NAME: ${{ secrets.PLAY_PACKAGE_NAME }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
packages: |
platform-tools
platforms;android-34
build-tools;34.0.0
- name: Gradle cache
uses: gradle/gradle-build-action@v3
- name: Restaurar keystore e credenciais do Play
run: |
echo "Decodificando keystore"
echo "$ANDROID_KEYSTORE_PASSWORD" > /dev/null
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > keystore.jks
echo "Gravando service-account.json"
echo "$PLAY_SERVICE_ACCOUNT_JSON" > service-account.json
env:
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
- name: Build AAB (release)
run: |
export ANDROID_KEYSTORE_PATH=$GITHUB_WORKSPACE/keystore.jks
./gradlew --no-daemon clean bundleRelease
- name: Publicar na track internal
run: |
export ANDROID_KEYSTORE_PATH=$GITHUB_WORKSPACE/keystore.jks
./gradlew --no-daemon publishRelease
- name: Upload do artefato (.aab)
uses: actions/upload-artifact@v4
with:
name: app-release-aab
path: app/build/outputs/bundle/release/*.aab
Passo 5 — Publicar no rollout internal e boas práticas
A track internal libera a versão para testers rapidamente e sem exposição pública. Crie grupos e listas de emails no Play Console para receberem as builds internas.
Você pode manter o status como draft para revisão manual e, depois, promover para completed. Isso dá controle e reduz risco.
Se seu projeto tiver outros deploys automatizados, veja também padrões de CI/CD em guia de CI/CD com GitHub Actions para PHP/Laravel para adaptar ideias ao Android.
- Defina grupos de teste internos antes da primeira publicação.
- Use status draft inicialmente e automatize a promoção conforme maturidade.
- Evite publicar a partir de PRs de forks; limite o workflow a branches protegidas.
- Guarde o keystore fora do repo; use somente secrets.
- Ajuste o targetSdk e o build-tools no setup do SDK conforme seu projeto.
Como confirmar que funcionou e solução de problemas comuns
Valide a publicação e investigue falhas rapidamente. Abaixo, um checklist de verificação e erros comuns com suas causas prováveis.
Para padronizar infra de runners em escala, veja práticas de auto‑escalar runners self‑hosted no GitHub Actions e complemente com o seu contexto.
- No GitHub Actions, verifique o job "Publicar na track internal" sem erros.
- Confirme o artefato .aab no passo de upload.
- No Play Console, veja a versão em Testes internos com o versionCode correto.
- Teste a instalação via link de teste interno enviado aos grupos.
- Erros de keystore: alias errado ou arquivo corrompido (base64 incorreto).
- Permissões insuficientes da conta de serviço: ajuste o papel no Play Console.
- Conflito de versionCode: incremente versionCode no Gradle.
- SDK faltando: alinhe platforms/build-tools no setup com o compileSdk do projeto.
Perguntas frequentes
Preciso usar runners self‑hosted para Android?
Não. O ubuntu‑latest atende a maioria dos casos quando você instala o Android SDK no job. Runners self‑hosted só fazem sentido se você precisa de builds ainda mais rápidos, cache pesado ou acesso a recursos de rede internos.
Como gerar o base64 do keystore com segurança?
Use a ferramenta nativa do seu sistema. No Linux e macOS: base64 < seu-keystore.jks > keystore.b64. No Windows, use o PowerShell: [Convert]::ToBase64String([IO.File]::ReadAllBytes('seu-keystore.jks')). Guarde o arquivo .b64 fora do repositório.
O Gradle Play Publisher é obrigatório para publicar?
Não. Você pode usar outras ferramentas como Fastlane ou a API diretamente. O plugin facilita no Gradle, pois integra assemble e publish em uma única pipeline. O processo de secrets e keystore continua semelhante.
Posso publicar apenas em tags para evitar releases acidentais?
Sim. Ajuste o gatilho do workflow para on: push: tags: ['v*']. Outra opção é exigir revisão de código e proteger a branch principal, evitando execuções não planejadas de publicação.
Quanto tempo leva para aparecer para testers na faixa internal?
Geralmente é rápido, variando de poucos minutos a algum tempo, dependendo de verificações automáticas. Garanta que os testers foram adicionados corretamente aos grupos e que o app cumpre políticas e requisitos mínimos do Play.
Como reverter uma versão enviada por engano?
Na faixa internal, você pode criar rapidamente uma nova versão com correção e versionCode maior. Para impedir novas publicações acidentais, troque o status para draft no Gradle ou restrinja o gatilho do workflow.
Quer adaptar o pipeline ao seu projeto Android?
Se você precisa discutir ajustes finos (matriz de módulos, múltiplos flavors, tracks diferentes), fale comigo e montamos um plano seguro.
Falar sobre CI AndroidVeja também
- tutorial: implementar Canary releases com Traefik em Docker Compose usando headers e weight routing para deploys graduais de aplicações PHP
- Tutorial: configurar HAProxy com Let's Encrypt e healthchecks para balanceamento de tráfego entre containers Docker em VPS (passo a passo)
- Tutorial prático: implementar mTLS entre Nginx e microserviços usando smallstep CA em Docker Compose
- Tutorial: configurar cgroup v2 e systemd ResourceControl para limitar CPU, memória e I/O de containers Docker no Debian