Android

Build, sign, and publish to Google Play — from Claude Code or the CLI. No Android Studio, no local SDK.

How it works

When you run submit_app, PromptShip:

  1. Clones your GitHub repo
  2. Runs ./gradlew assembleRelease on a dedicated build server
  3. Signs the APK with your keystore (auto-generated on first submit if you don't bring your own)
  4. Uploads the signed APK to Google Play via the Play Developer API

No Dockerfile needed. No CI/CD setup. Just a standard Android repo.

Prerequisites

First release? Google requires at least one manually uploaded release before the API can be used. Create the app in Play Console and upload an APK/AAB manually once, then PromptShip can take over for all subsequent releases.

Step 1 — Create & configure the app

In Claude Code (or your AI tool):

Create a PromptShip app for my Android repo github.com/me/my-android-app

PromptShip will call create_app and then configure_app with app_type="android" and your package name. No Dockerfile is needed — PromptShip handles the build environment automatically.

Or via CLI:

promptship apps create my-android-app --repo github.com/me/my-android-app
promptship apps configure my-android-app --app-type android --android-package com.example.myapp

Step 2 — Set up Google Service Account

PromptShip uses a Google service account to upload builds to Play Store on your behalf. You need to create one and grant it access.

Note: A screen recording walkthrough will appear here once recorded. The text steps below cover the full process.

Step-by-step

1. Link your Google Cloud project in Play Console

  1. Open Google Play Console
  2. Go to Setup → API access
  3. Click Link to a Google Cloud Project — either create a new project or link an existing one
  4. Click View in Google Cloud Console to open the linked project

2. Create a service account

  1. In Google Cloud Console, go to IAM & Admin → Service Accounts
  2. Click Create Service Account
  3. Give it a name like promptship-play and click Create and Continue
  4. Skip the optional role and user access steps — click Done

3. Grant the service account access in Play Console

  1. Back in Play Console → Setup → API access, find your newly created service account
  2. Click Manage Play Console permissions next to it
  3. Under App permissions, select your app and grant the Release manager role
  4. Click Apply and then Save changes

4. Download the JSON key

  1. In Cloud Console → IAM & Admin → Service Accounts, click on your service account
  2. Go to the Keys tab → Add Key → Create new key
  3. Select JSON and click Create — a .json file downloads automatically

5. Set the secret in PromptShip

In Claude Code:

Set the GOOGLE_SERVICE_ACCOUNT_JSON secret for my-android-app to the contents of service-account.json

Or via CLI:

promptship secrets set GOOGLE_SERVICE_ACCOUNT_JSON="$(cat service-account.json)" --app my-android-app --env prod

Step 3 — Submit to Google Play

In Claude Code:

Submit my-android-app to Google Play internal track from branch main

Or via CLI:

promptship submit-app --app my-android-app --env prod --branch main --track internal

play_track options:

The first build takes 3–5 minutes. Subsequent builds are faster as Gradle caches are warmed.

Keystore management

On your first submission, PromptShip auto-generates a PKCS12 keystore and stores it securely. The same keystore is used for all future submissions — this is important for Google Play, which requires the same signing key for updates.

Download your keystore

To back up your keystore or migrate to another CI system:

promptship apps download-keystore my-android-app

This saves the keystore as my-android-app.p12 in the current directory and prints the key alias and password. Keep these safe — Google Play requires the same signing key for all future updates.

Bring your own keystore (BYOK)

If you already have a keystore (e.g. from Android Studio), set these secrets before your first submit:

ANDROID_KEYSTORE_B64       — base64-encoded PKCS12 keystore
ANDROID_KEYSTORE_PASSWORD  — keystore password
ANDROID_KEYSTORE_KEY_ALIAS — key alias within the keystore

Encode your existing keystore:

# macOS (encode to base64)
base64 -i my-app.jks
# Linux (encode to base64, no line wrapping)
base64 -w0 my-app.jks

Secrets reference

All Android secrets are set with set_secret / promptship secrets set. They are read at build time only — never injected into the app binary. See Secrets for full details.

SecretRequiredDescription
GOOGLE_SERVICE_ACCOUNT_JSONYesGoogle service account JSON key for Play Store upload (see Step 2 above)
ANDROID_KEYSTORE_B64NoBase64-encoded PKCS12 keystore — auto-generated on first submit if not set
ANDROID_KEYSTORE_PASSWORDNoKeystore password — required if ANDROID_KEYSTORE_B64 is set
ANDROID_KEYSTORE_KEY_ALIASNoKey alias — required if ANDROID_KEYSTORE_B64 is set

Troubleshooting

"Permission denied" on Play Store upload

The service account does not have the Release manager role on the app. Go back to Play Console → Setup → API access and verify the role is set at the app level (not just account level). Changes can take a few minutes to propagate.

"Package name not found"

The android_package_name in your PromptShip config must exactly match the applicationId in your build.gradle and the package name in Play Console.

API access not available

Google requires at least one manually uploaded APK/AAB in Play Console before the Developer API is enabled for your app. Upload one via Play Console → Production (or Internal Testing) → Create new release, then try again.

Gradle build fails

Check that ./gradlew assembleRelease runs cleanly in your local environment. Common issues: missing google-services.json (add it to your repo or set it as a secret), missing signing config (PromptShip injects this automatically — ensure you haven't hardcoded a local keystore path in build.gradle).