DEV Community

Guillermo
Guillermo

Posted on

How to Automate Google Play Releases Without Losing Your Mind

Intro

Let’s be honest.

Publishing an Android app to Google Play manually is already annoying…

but automating it? That’s where things usually get messy.

If you’ve ever tried, you probably ended up with:

  • a random JSON key sitting in your repo 😬
  • a CI pipeline you don’t fully trust
  • or a setup you’re afraid to touch because “it works… somehow”

I’ve been there.

So this post is the version I wish I had earlier:

a clean, secure way to automate Google Play releases without hacks, without leaking secrets, and without overcomplicating everything.

meme

The Key Idea

Instead of storing a Google service account key in your repo (please don’t), we use:

  • Workload Identity Federation (WIF)
  • Service account impersonation

In plain English:

Your CI logs into Google using short-lived tokens — no permanent secrets needed.


What You’ll Get

By the end of this:

  • Your app builds automatically
  • Your AAB gets uploaded to Google Play
  • No credentials stored in your repo
  • A setup you won’t be scared to touch later

Quick Setup (Copy & Paste)

1. Define variables

PROJECT_ID="your-project-id"
PROJECT_NUMBER="your-project-number"
POOL_ID="github"
PROVIDER_ID="ci-provider"
SERVICE_ACCOUNT_NAME="ci-publisher"
SERVICE_ACCOUNT_EMAIL="ci-publisher@your-project-id.iam.gserviceaccount.com"
REPO="your-org/your-repo"
PACKAGE_NAME="com.your.app"
Enter fullscreen mode Exit fullscreen mode

2. Create service account

gcloud iam service-accounts create "$SERVICE_ACCOUNT_NAME" \
  --project="$PROJECT_ID"
Enter fullscreen mode Exit fullscreen mode

3. Create identity pool

gcloud iam workload-identity-pools create "$POOL_ID" \
  --project="$PROJECT_ID" \
  --location="global"
Enter fullscreen mode Exit fullscreen mode

4. Connect your CI (OIDC)

gcloud iam workload-identity-pools providers create-oidc "$PROVIDER_ID" \
  --project="$PROJECT_ID" \
  --location="global" \
  --workload-identity-pool="$POOL_ID" \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.ref=assertion.ref" \
  --attribute-condition="assertion.repository == '$REPO'"
Enter fullscreen mode Exit fullscreen mode

5. Allow impersonation

gcloud iam service-accounts add-iam-policy-binding \
  "$SERVICE_ACCOUNT_EMAIL" \
  --project="$PROJECT_ID" \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/attribute.repository/$REPO"
Enter fullscreen mode Exit fullscreen mode

6. Enable Play API

gcloud services enable androidpublisher.googleapis.com \
  --project="$PROJECT_ID"
Enter fullscreen mode Exit fullscreen mode

7. Configure Play Console (manual)

  • Go to Users and permissions
  • Add the service account email
  • Give access to your app
  • Grant publish permissions (internal track is enough)

8. Add CI secrets

Workload Identity Provider

projects/YOUR_PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL/providers/PROVIDER
Enter fullscreen mode Exit fullscreen mode

Service Account

ci-publisher@your-project-id.iam.gserviceaccount.com
Enter fullscreen mode Exit fullscreen mode

9. Add CI workflow

name: Publish Android to Play

on:
  push:
    tags:
      - "v*"

permissions:
  contents: read
  id-token: write

jobs:
  publish:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@vX

      - name: Authenticate
        uses: google-github-actions/auth@v3
        with:
          workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
          service_account: ${{ secrets.SERVICE_ACCOUNT }}

      - name: Build
        run: ./gradlew bundleRelease

      - name: Upload
        uses: r0adkll/upload-google-play@v1
        with:
          serviceAccountJson: ${{ steps.auth.outputs.credentials_file_path }}
          packageName: com.your.app
          releaseFiles: app/build/outputs/bundle/release/*.aab
          track: internal
Enter fullscreen mode Exit fullscreen mode

10. Trigger a release

git tag v1.0.0
git push origin v1.0.0
Enter fullscreen mode Exit fullscreen mode

Debug Checklist

If something breaks, check this first:

  • Is the provider pointing to the correct repo?
  • Does your secret include /providers/...?
  • Did you add id-token: write?
  • Is the service account added in Play Console?

Common Mistakes

Auth works but upload fails

Play Console permissions are wrong.

Auth fails completely

Repository or branch does not match the provider condition.

Token errors

Missing id-token: write permission.


Final Thoughts

This setup might look complex at first…

but once it’s in place, it just works.

And more importantly:

  • no leaked keys
  • no fragile hacks
  • no future headaches

Just a clean pipeline doing its job.


TL;DR

  • Don’t store Google service account keys
  • Use Workload Identity Federation
  • Let CI impersonate a service account
  • Upload with a GitHub Action
  • Sleep better at night 😄

Top comments (0)