Skip to content

Android Builds

Build and submit Android apps to the Google Play Store using Capgo’s secure cloud infrastructure.

Android builds run in secure Cloudflare sandboxes:

  • Infrastructure: Cloudflare Workers with containerized Android SDK
  • Build Tool: Gradle with Android build tools
  • Execution: Isolated sandbox environment per build
  • Cleanup: Instant deletion after build completion
  • Security: No persistent storage, complete isolation between builds

Before building for Android, you need:

  • Android Studio installed locally (for initial keystore setup)
  • Your app building successfully with npx cap open android
  • Java JDK 17 or higher

For release builds, you need a signing keystore:

Build TypeKeystore RequiredPurpose
DebugNoTesting only, auto-generated
ReleaseYesPlay Store submission

If you don’t have a keystore yet, create one:

Terminal window
keytool -genkey -v \
-keystore my-release-key.keystore \
-alias my-key-alias \
-keyalg RSA \
-keysize 2048 \
-validity 10000

Answer the prompts:

  • Password: Choose a strong password (save it securely!)
  • Name: Your name or company name
  • Organization: Your company name
  • Location: Your city, state, country

When creating a keystore, you’ll need to remember:

  1. Keystore Password (KEYSTORE_STORE_PASSWORD): The password for the keystore file itself
  2. Key Alias (KEYSTORE_KEY_ALIAS): The name/identifier for your signing key within the keystore
  3. Key Password (KEYSTORE_KEY_PASSWORD): The password for the specific key (can be the same as store password)

Example workflow:

Terminal window
# List aliases in your keystore to verify
keytool -list -keystore my-release-key.keystore
# View detailed information about your key
keytool -list -v -keystore my-release-key.keystore -alias my-key-alias

For release builds, set these credentials:

Terminal window
# Android Signing (Required for release)
ANDROID_KEYSTORE_FILE="<base64-encoded-keystore>"
KEYSTORE_KEY_ALIAS="my-key-alias"
KEYSTORE_KEY_PASSWORD="<key-password>"
KEYSTORE_STORE_PASSWORD="<store-password>"
# Play Store Publishing (Optional, for auto-submission)
PLAY_CONFIG_JSON="<base64-encoded-service-account-json>"

Keystore File:

Terminal window
base64 -i my-release-key.keystore | pbcopy

Play Store Service Account JSON:

Terminal window
base64 -i play-store-service-account.json | pbcopy

The base64 string is now in your clipboard.

To enable automatic Play Store uploads, you need to create a Google Cloud service account with proper permissions.

  1. Create Service Account in Google Cloud

    • Go to Google Play Console → Setup → API Access
    • Click “Create new service account”
    • Follow the link to Google Cloud Console
    • Click “Create Service Account”
    • Enter a name (e.g., “Capgo CI/CD”)
    • Grant the “Service Account User” role
    • Click “Done”
  2. Create JSON Key

    • In Google Cloud Console, find your service account
    • Click on the service account email
    • Go to “Keys” tab
    • Click “Add Key” → “Create new key”
    • Choose “JSON” format
    • Download the JSON file (keep it secure!)
  3. Grant Permissions in Play Console

    • Go back to Google Play Console → Setup → API Access
    • Find your service account in the list
    • Click “Grant access”
    • Under “App permissions”, select your app
    • Under “Account permissions”, grant:
      • Releases: “View app information and download bulk reports (read-only)”
      • Releases: “Create, edit, and delete draft releases”
      • Releases: “Release to production, exclude devices, and use Play App Signing”
    • Click “Invite user”
  4. Accept the Invitation

    • The service account will receive an invitation email
    • Accept the invitation to activate the permissions

Perfect for testing without signing:

Terminal window
npx @capgo/cli@latest build com.example.app \
--platform android \
--build-mode debug

This creates a debug APK that can be installed on any device for testing.

For Play Store submission:

Terminal window
npx @capgo/cli@latest build com.example.app \
--platform android \
--build-mode release

Requires signing credentials to be configured as environment variables.

name: Build Android App
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install dependencies
run: npm ci
- name: Build web assets
run: npm run build
- name: Sync Capacitor
run: npx cap sync android
- name: Build Android app
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
ANDROID_KEYSTORE_FILE: ${{ secrets.ANDROID_KEYSTORE }}
KEYSTORE_KEY_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
KEYSTORE_KEY_PASSWORD: ${{ secrets.KEYSTORE_KEY_PASSWORD }}
KEYSTORE_STORE_PASSWORD: ${{ secrets.KEYSTORE_STORE_PASSWORD }}
PLAY_CONFIG_JSON: ${{ secrets.PLAY_STORE_CONFIG }}
run: |
npx @capgo/cli@latest build ${{ secrets.APP_ID }} \
--platform android \
--build-mode release
  1. Sandbox Initialization (~5 seconds)

    • Secure container spun up
    • Android SDK and Gradle loaded
    • Isolated file system created
  2. Project Setup (~20 seconds)

    • Project zip downloaded from R2
    • Extracted to build directory
    • Signing credentials injected
  3. Gradle Build (2-4 minutes)

    • Dependencies downloaded
    • APK/AAB compilation
    • ProGuard/R8 optimization (release mode)
    • Code signing applied
  4. Play Store Upload (30 seconds, if configured)

    • AAB uploaded to Play Console
    • Release track configured
    • Submission initiated
  5. Cleanup (immediate)

    • All files deleted
    • Container destroyed
    • No artifacts retained

Our Android build environment includes:

  • Java: OpenJDK 17
  • Android SDK: Latest stable
  • Gradle: 8.x
  • Build Tools: 34.x
  • Node.js: 18.x (LTS)
  • NPM: Latest stable
  • APK (Android Package): Installable file for direct installation
  • AAB (Android App Bundle): Google Play’s recommended format (smaller downloads for users)

By default, Capgo builds create:

  • Debug mode: APK
  • Release mode: AAB (optimized for Play Store)

Typical Android build times:

Build TypeAverage Time
Debug2-3 minutes
Release (no ProGuard)3-4 minutes
Release (with ProGuard)4-6 minutes

If your app has custom build variants (e.g., staging, production), use build-config:

Terminal window
npx @capgo/cli@latest build com.example.app \
--platform android \
--build-mode release \
--build-config '{"variant":"staging"}'

This will build the stagingRelease variant.

For apps with flavor dimensions:

Terminal window
--build-config '{"flavor":"premium","variant":"production"}'

This builds the premiumProductionRelease variant.

“Keystore password incorrect”

  • Verify KEYSTORE_STORE_PASSWORD matches your keystore
  • Ensure KEYSTORE_KEY_PASSWORD matches your key alias password
  • Check for extra spaces or special characters

“Key alias not found”

  • Verify KEYSTORE_KEY_ALIAS matches exactly (case-sensitive)
  • List aliases: keytool -list -keystore my-release-key.keystore

“Gradle build failed”

  • Check build logs for the specific error
  • Ensure your app builds locally with ./gradlew assembleRelease
  • Verify all native dependencies are in build.gradle

“Play Store upload failed”

  • Verify service account JSON is valid
  • Ensure service account has correct permissions in Play Console
  • Check that app is properly set up in Play Console

“Build timeout”

  • Large apps may need optimization
  • Check if unnecessary dependencies can be removed
  • Contact support if builds consistently timeout

Watch for these key phases in the build logs:

→ Downloading dependencies...
→ Running Gradle assembleRelease...
→ Signing APK/AAB...
→ Uploading to Play Store...
✔ Build succeeded

If a build fails, the specific Gradle error will be shown in the logs.

Always ensure your Android build works locally:

Terminal window
cd android
./gradlew assembleRelease
# or
./gradlew bundleRelease
  • Never commit keystores to version control
  • Store in secure secrets management (1Password, AWS Secrets Manager, etc.)
  • Keep backup copies in multiple secure locations
  • Document passwords in a secure password manager

Capgo reads version from your capacitor.config.json:

{
"appId": "com.example.app",
"appName": "My App",
"version": "1.0.0",
"build": "1"
}

Increment the build number for each release.

For release builds, ensure ProGuard rules are properly configured:

android/app/proguard-rules.pro
-keep class com.getcapacitor.** { *; }
-keep @com.getcapacitor.annotation.CapacitorPlugin public class * {
@com.getcapacitor.annotation.PluginMethod public <methods>;
}

Keep an eye on APK/AAB size to ensure it’s optimized:

The CLI shows final size:
→ APK size: 12.4 MB

If your app is large (>50 MB), consider:

  • Enabling ProGuard/R8
  • Using AAB format (dynamic delivery)
  • Optimizing images and assets

With PLAY_CONFIG_JSON configured, builds are automatically uploaded to Play Console’s internal testing track.

If you prefer manual submission:

  1. Run the build without PLAY_CONFIG_JSON
  2. Download the AAB from build artifacts (if configured)
  3. Upload manually to Play Console