Tutorial: configurar pipeline CI para Android com GitHub Actions, proteger keystore e publicar rollout internal — passo a passo

Apps mobile · Por · Publicado em · Atualizado em · 9 min de leitura

Mãos segurando smartphone com tela branca sobre mesa com teclado e bloco de notas
Imagem ilustrativa para tutorial CI Android e publicação interna Foto: Towfiqu barbhuiya / Pexels

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 Android

Veja também