Tutorial: configurar pipeline CI para Android con GitHub Actions, proteger el keystore y publicar en la track internal — paso a paso

Apps mobile · Por · Publicado el · Actualizado el · 9 min de lectura

Manos sosteniendo un smartphone con pantalla blanca sobre una mesa con teclado y libreta
Imagen ilustrativa para tutorial CI Android y publicación interna Foto: Towfiqu barbhuiya / Pexels

Este es el tutorial para configurar un pipeline CI para Android con GitHub Actions, proteger el keystore y publicar en la track internal. Prepararás secrets, ajustarás Gradle, escribirás el workflow YAML y validarás la publicación. Es una guía directa para firmar la app de forma segura y automatizar el envío a testers internos.

Prerequisitos

Necesitas preparar varios elementos antes de automatizar el build y la publicación. Aseguran que el pipeline se ejecute sin interrupciones y con seguridad.

Si tu proyecto aún no publica manualmente, revisa el flujo de firmado y la versión local antes de automatizar. Para conocer el envío manual, consulta la guía sobre la Play Store en Publicar una app Android en Google Play.

  • Proyecto Android con el plugin Android Gradle funcionando localmente.
  • Cuenta en Google Play Console con la app ya creada (packageName definido).
  • Cuenta de servicio en el Play Console con clave JSON descargada y permiso de publicador.
  • Keystore de firma de la app (JKS o PKCS12) y contraseñas asociadas.
  • Repositorio en GitHub con GitHub Actions habilitado.
  • Java 17 en el build (AGP recientes lo requieren).

Visión general del pipeline CI/CD

Vamos a montar un pipeline que: firma la app, genera el bundle (.aab) y publica en la track internal. Tendrás un workflow único con pasos encadenados. Esto puede publicar una versión para testers, así que usa ramas protegidas.

Si quieres ver un pipeline de deploy genérico con Actions, revisa también este pipeline de despliegue automático con GitHub Actions y complementa tu lectura.

  • Checkout del código y caché de Gradle.
  • Instalación de Java y del Android SDK necesario.
  • Restauración del keystore a partir de secrets.
  • Generación del app bundle con Gradle (bundleRelease).
  • Publicación automática con Gradle Play Publisher en la track internal.
  • Upload del artefacto como evidencia del build.

Paso 1 — Configurar firma y Play en Gradle

Prepara tu módulo app para leer variables de entorno en signingConfig y habilita la publicación vía el plugin de Play. Sustituye la versión del plugin por la actual y ajusta minify/proguard según tu proyecto.

El archivo JSON de la cuenta de servicio se creará en el workspace del Actions durante el job. Mantenemos la ruta simple (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
}

Paso 2 — Crear cuenta de servicio en Play Console

Crea una cuenta de servicio vinculada a la app en el Play Console y genera la clave JSON. Concede solo los permisos necesarios para publicar en la track internal.

Guarda el JSON con cuidado. Si se filtra, revoca y genera una nueva clave inmediatamente.

Anota el packageName exacto de la app. Se usará el plugin para localizar la aplicación.

  • Ve a Acceso a la API en el Play Console y vincula al Google Cloud.
  • Crea una cuenta de servicio y genera la clave JSON.
  • Asigna permisos de publicación a la app objetivo.
  • Descarga el archivo JSON y almacénalo en un lugar seguro.

Paso 3 — Añadir secrets en GitHub con seguridad

Vamos a almacenar todo como secrets. Para el keystore, usa base64 para evitar problemas binarios. En el workflow decodificaremos a un archivo .jks.

En el repositorio, accede a Settings > Secrets and variables > Actions y crea los siguientes secrets.

Nombre del secret Contenido Consejo
ANDROID_KEYSTORE_BASE64 Keystore (.jks o .p12) en base64 Usa base64 en tu SO; evita pegar archivos binarios directamente.
ANDROID_KEYSTORE_PASSWORD Contraseña del keystore No reutilices contraseñas entre entornos.
ANDROID_KEY_ALIAS Alias de la clave de firma Confirma el alias con keytool si tienes dudas.
ANDROID_KEY_PASSWORD Contraseña del alias Puede ser igual a la del keystore, pero no es obligatorio.
PLAY_SERVICE_ACCOUNT_JSON Contenido del JSON de la cuenta de servicio Pega el JSON completo; el workflow creará el archivo.
PLAY_PACKAGE_NAME Package name de la app (ej.: com.seu.pacote) Mantén el valor explícito para validaciones.

Paso 4 — Workflow YAML de GitHub Actions

Abajo tienes un workflow funcional. Instala Java 17, prepara el Android SDK, restaura el keystore, genera el .aab y publica en la track internal. Esto ejecuta la publicación, así que restringe el trigger según tu política (ej.: solo 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

Paso 5 — Publicar en el rollout internal y buenas prácticas

La track internal libera la versión a testers rápidamente y sin exposición pública. Crea grupos y listas de emails en Play Console para que reciban las builds internas.

Puedes mantener el status como draft para revisión manual y luego promover a completed. Esto da control y reduce riesgos.

Si tu proyecto tiene otros despliegues automatizados, consulta también patrones de CI/CD en la guía CI/CD con GitHub Actions para PHP/Laravel y adapta ideas al Android.

  • Define grupos de test internos antes de la primera publicación.
  • Usa status draft inicialmente y automatiza la promoción según la madurez.
  • Evita publicar desde PRs de forks; limita el workflow a ramas protegidas.
  • Guarda el keystore fuera del repo; usa solo secrets.
  • Ajusta targetSdk y build-tools en el setup del SDK según tu proyecto.

Cómo confirmar que funcionó y solución de problemas comunes

Valida la publicación e investiga fallos rápidamente. Abajo tienes una lista de verificación y errores comunes con sus causas probables.

Para estandarizar infra de runners a escala, consulta prácticas de autoescalar runners self-hosted en GitHub Actions y complétalas con tu contexto.

  • En GitHub Actions, verifica el job "Publicar na track internal" sin errores.
  • Confirma el artefacto .aab en el paso de upload.
  • En Play Console, comprueba la versión en Testes internos con el versionCode correcto.
  • Prueba la instalación vía el enlace de test interno enviado a los grupos.
  • Errores de keystore: alias incorrecto o archivo corrupto (base64 mal generado).
  • Permisos insuficientes de la cuenta de servicio: ajusta el rol en Play Console.
  • Conflicto de versionCode: incrementa versionCode en Gradle.
  • SDK faltante: alinea platforms/build-tools en el setup con el compileSdk del proyecto.

Preguntas frecuentes

¿Necesito usar runners self‑hosted para Android?

No. ubuntu-latest cubre la mayoría de los casos cuando instalas el Android SDK en el job. Los runners self-hosted solo tienen sentido si necesitas builds mucho más rápidos, caché intensivo o acceso a recursos de red internos.

¿Cómo generar el base64 del keystore con seguridad?

Usa la herramienta nativa de tu sistema. En Linux y macOS: base64 < tu-keystore.jks > keystore.b64. En Windows PowerShell: [Convert]::ToBase64String([IO.File]::ReadAllBytes('tu-keystore.jks')). Guarda el .b64 fuera del repositorio.

¿El Gradle Play Publisher es obligatorio para publicar?

No. Puedes usar otras herramientas como Fastlane o la API directamente. El plugin facilita en Gradle porque integra assemble y publish en una única pipeline. El manejo de secrets y el keystore es similar.

¿Puedo publicar solo en tags para evitar releases accidentales?

Sí. Ajusta el trigger del workflow a on: push: tags: ['v*']. Otra opción es exigir revisión de código y proteger la rama principal para evitar ejecuciones no planificadas de publicación.

¿Cuánto tarda en aparecer para testers en la track internal?

Suele ser rápido, desde pocos minutos hasta algo más, según verificaciones automáticas. Asegúrate de que los testers estén añadidos correctamente a los grupos y que la app cumpla políticas y requisitos mínimos del Play.

¿Cómo revertir una versión enviada por error?

En la track internal puedes crear rápidamente una nueva versión con la corrección y un versionCode mayor. Para evitar más publicaciones accidentales, cambia el status a draft en Gradle o restringe el trigger del workflow.

¿Quieres adaptar el pipeline a tu proyecto Android?

Si necesitas discutir ajustes finos (matriz de módulos, múltiples flavors, tracks distintas), háblame y montamos un plan seguro.

Hablar sobre CI Android

Ver también