Skip to content
All posts
July 4, 20263 min read

Setting Up CI/CD for Android with GitHub Actions

A practical GitHub Actions setup for Android — build, test, lint, and Play Store publish on a solo dev workflow. No fluff, no enterprise-scale overhead.

AndroidCI/CDGitHub ActionsAutomation
Share:

CI/CD for Android has a reputation for being complicated to set up. Here's a practical workflow for solo developers — covering build, test, lint, and Play Store publish.

The basic build and test workflow

yaml
name: Android CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: gradle

      - name: Run lint
        run: ./gradlew lint

      - name: Run unit tests
        run: ./gradlew testDebugUnitTest

      - name: Build debug APK
        run: ./gradlew assembleDebug

      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-results
          path: app/build/reports/tests/

This runs on every push and PR. If lint or tests fail, the workflow fails — you know before merging.

Caching Gradle dependencies

Without caching, a fresh dependency download adds 3–5 minutes per run:

yaml
- name: Cache Gradle
  uses: actions/cache@v4
  with:
    path: |
      ~/.gradle/caches
      ~/.gradle/wrapper
    key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
    restore-keys: |
      ${{ runner.os }}-gradle-

The cache key hashes your Gradle files, so it invalidates correctly when dependencies change.

Signing release builds — via secrets only

Never commit keystore files. Store everything in GitHub Secrets under your repo settings. Read all credentials from environment variables in your

code
build.gradle.kts
— never hardcode them in any file that gets committed.

The workflow decodes the keystore at build time from a base64-encoded secret, builds the AAB, and the file is gone when the runner exits. Nothing sensitive ever touches the repo.

Play Store publish via Fastlane

yaml
- name: Setup Ruby
  uses: ruby/setup-ruby@v1
  with:
    ruby-version: '3.2'
    bundler-cache: true

- name: Publish to Play Store (internal track)
  run: bundle exec fastlane supply
  env:
    SUPPLY_JSON_KEY_DATA: ${{ secrets.PLAY_STORE_JSON_KEY }}
    SUPPLY_TRACK: internal
    SUPPLY_AAB: app/build/outputs/bundle/release/app-release.aab

code
PLAY_STORE_JSON_KEY
is a service account JSON key from Google Play Console with publishing permissions. Create it under Play Console → Setup → API access.

Separate release workflow triggered by tags

Don't publish to Play Store on every push. Use a separate workflow on tags:

yaml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      # build, sign, publish steps

Tag a release with

code
git tag v1.2.3 && git push --tags
and the publish workflow fires automatically.

Running tests on a schedule

Catch regressions from dependency updates even when you haven't pushed:

yaml
on:
  schedule:
    - cron: '0 6 * * 1'  # Every Monday at 6am
  workflow_dispatch:       # Manual trigger

What this gives you

  • Every PR validated before merging
  • Lint and tests run without manual effort
  • Release builds produced consistently from a clean environment
  • Play Store publishes triggered by a single git tag, not manual steps

The GitHub Actions free tier gives 2,000 minutes/month — more than enough for a solo Android project. A typical build + test run takes 4–6 minutes, so you have capacity for 300+ runs per month before hitting limits.

The upfront setup cost is an hour. The ongoing benefit is every release decision backed by a green CI run rather than a mental checklist.

Share:
S

Sudarshan Chaudhari

AI Systems Builder / Product Engineer

Bangkok, Thailand

Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Related Apps

MyFamilyTracker

Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus