The Play publish workflow uses distribution/whatsnew/whatsnew-en-US (its whatsNewDirectory), NOT the fastlane changelogs/*.txt (those feed F-Droid). That file was stale at v0.4.7 — so 0.4.8/0.4.9/0.4.10 all shipped to the internal track with outdated release notes. Updated it to 0.4.10 (<500 chars). Also corrected PUBLISHING.md, which I'd previously written wrong: (a) app.json android.versionCode is overridden by CI (github.run_number+100), so 0.4.10's real Play versionCode is 142, not the app.json value — hand-bumping it is pointless for Play; (b) Play release notes live in distribution/whatsnew, not fastlane changelogs. Discovered while promoting 0.4.10 (the Console showed versionCode 142, not the app.json 37). Claude-Session: https://claude.ai/code/session_01T12AhSnQVrSxNnvwfCx2z6 Co-authored-by: engineer <engineer@macbookpro.lan> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
3.8 KiB
3.8 KiB
Publishing to Google Play Store
Required GitHub Secrets
Configure these in Settings > Secrets and variables > Actions:
| Secret | Description |
|---|---|
PLAY_STORE_SERVICE_ACCOUNT_JSON |
Google Play Console service account JSON key (full JSON content) |
KEYSTORE_BASE64 |
Base64-encoded release keystore (base64 -w0 release.keystore) |
KEYSTORE_PASSWORD |
Keystore password |
KEY_ALIAS |
Key alias in the keystore |
KEY_PASSWORD |
Key password |
Setup Steps
1. Create a release keystore
keytool -genkeypair -v -storetype PKCS12 \
-keystore release.keystore -alias release \
-keyalg RSA -keysize 2048 -validity 10000
Encode it for GitHub secrets:
base64 -w0 release.keystore
2. Create a Google Play service account
- Go to Google Cloud Console > IAM > Service Accounts
- Create a service account and download the JSON key
- In Google Play Console > Settings > API access, link the service account
- Grant it release management permissions for your app
3. Workflow triggers
The publish workflow runs on:
- GitHub Release publish events
- Tag pushes matching
v*
It builds an AAB (Android App Bundle), signs it with the release keystore, and uploads to the internal track. Promote to production via Play Console.
Releasing (proven runbook)
- Bump
versioninpackage.jsonandapp.json(expo.version). Do not bother hand-bumpingandroid.versionCodefor Play — the publish workflow overrides it withgithub.run_number + 100at build time (so the PlayversionCodeis e.g.142, unrelated to the number inapp.json; that field only matters for local/other builds). - Update the Play release notes in
distribution/whatsnew/whatsnew-en-US(single file, applied to the build being uploaded; max 500 chars). This — not thefastlane/metadata/android/en-US/changelogs/*.txtfiles — is what the Play publish uses (whatsNewDirectoryin the workflow). The fastlanechangelogs/*.txtfiles feed F-Droid, not Play; keep them for F-Droid but don't expect Play to read them. Merge tomain. - Tag the release:
git tag -a vX.Y.Z <sha> -m "..." && git push origin vX.Y.Z. This triggers the publish workflow → internal track. - Verify the publish run is green, then confirm the build on the internal track. Note its real Play
versionCode(run_number+100) — that's what you promote, not theapp.jsonnumber. - Promote to production (see below).
Promoting to production
Production is not published by CI by default — the service account is scoped to the internal track only, which is intentional (a human gate before a build reaches all users).
- Recommended — Play Console: Production → Create release → Add from library → select the build by its versionName (e.g.
0.4.10) and confirm itsversionCode(the run_number-derived one, e.g.142— not theapp.jsonnumber) → review → roll out. If the "What's new" field is empty, paste fromdistribution/whatsnew/whatsnew-en-US. No rebuild. - Fully automated (optional): grant the CI service account "Release to production" for this app in Play Console → Users & permissions, then run the workflow's
workflow_dispatchwithtrack=production,status=completed. Without that permission the production dispatch fails withThe caller does not have permissionafter building — so don't dispatchtrack=productionuntil the service account has been granted production access.
Fastlane (Alternative)
A Fastlane setup is included for local publishing:
bundle install
bundle exec fastlane android deploy
Set environment variables: SUPPLY_JSON_KEY, RELEASE_STORE_FILE, RELEASE_STORE_PASSWORD, RELEASE_KEY_ALIAS, RELEASE_KEY_PASSWORD.