Android Production

main is the production branch. Every push to main that touches the Android app runs .github/workflows/android-production.yml. The current production channel is Google Play internal testing for the phone app package:
co.sapientic.everything
The workflow verifies both phone and Wear modules, builds unsigned release artifacts, signs the phone Android App Bundle in a separate no-checkout job, and publishes the signed phone bundle to the Google Play internal testing track. Wear OS has its own .github/workflows/android-wear-production.yml pipeline. It builds and signs the Wear App Bundle on main; Play publishing is gated by GOOGLE_PLAY_WEAR_PUBLISH_ENABLED=true because Play Console must first have the Wear form factor configured in Advanced settings.

GitHub secrets and variables

Add these repository secrets before relying on main as the Android production path:
ANDROID_RELEASE_KEYSTORE_BASE64
ANDROID_RELEASE_KEYSTORE_PASSWORD
ANDROID_RELEASE_KEY_ALIAS
ANDROID_RELEASE_KEY_PASSWORD
Google Play publishing should use GitHub OIDC / Google Workload Identity Federation. Configure these GitHub repository variables:
GOOGLE_WORKLOAD_IDENTITY_PROVIDER
GOOGLE_SERVICE_ACCOUNT_EMAIL
For Wear OS publishing, configure Play Console Advanced settings for the Wear form factor, then set this repository variable:
GOOGLE_PLAY_WEAR_PUBLISH_ENABLED=true
Keep it unset or false until Play Console accepts Wear track edits. The workflow will still build and sign Wear artifacts while publishing is disabled. To enable Firebase Remote Config in production builds, also add this repository variable:
FIREBASE_ANDROID_GOOGLE_SERVICES_JSON
This should be the full contents of the Android google-services.json file for package co.sapientic.everything. The workflow writes it into apps/android/app/google-services.json on the runner before Gradle builds the app. google-services.json is Firebase client configuration, not a production signing or publishing credential. Keep it out of the high-value GitHub secrets used for Play signing and publishing. ANDROID_RELEASE_KEYSTORE_BASE64 should be the base64 contents of the Play upload keystore file. The workflow decodes it only in the signing job and never commits the keystore. On Windows, generate the base64 value with:
[Convert]::ToBase64String([IO.File]::ReadAllBytes("C:\path\to\everything-upload-key.jks"))
Use a Play upload key, not the debug keystore.

Play Console setup

Create the app in Play Console with package name co.sapientic.everything, enroll it in Play App Signing, and create an internal testing tester list. Enable the Google Play Android Developer API, create a service account, and grant the service account app permission to release to testing tracks. Do not create or store a long-lived JSON key for CI publishing; the workflow requires Workload Identity Federation. If Google Play reports Package not found, create the app record in Play Console first and complete the initial setup needed for API uploads.

GitHub OIDC setup

Use Workload Identity Federation so GitHub Actions can publish without a long-lived JSON key. The current service account is:
github-play-publisher@sapientic-play-publishing.iam.gserviceaccount.com
Run this from Google Cloud Shell or a local shell authenticated with a Google account that can enable APIs and edit IAM:
powershell -ExecutionPolicy Bypass -File scripts/android/Setup-GitHubWorkloadIdentity.ps1
The script creates a workload identity pool/provider restricted to repository sapientic/sapientic and branch refs/heads/main, grants roles/iam.workloadIdentityUser on the Play publishing service account, and writes the GitHub repository variables used by the production workflow. If the repository still has an old GOOGLE_PLAY_SERVICE_ACCOUNT_JSON secret from earlier publishing setup, delete it after confirming Workload Identity Federation is configured.

Firebase Remote Config setup

In Firebase Console, add or open the Firebase project for Everything, register an Android app with package co.sapientic.everything, download google-services.json, and store the file contents in the GitHub repository variable FIREBASE_ANDROID_GOOGLE_SERVICES_JSON. Create a Remote Config parameter named home_screen_json with the server-driven home-screen schema:
{
  "schemaVersion": 1,
  "topBarTitle": "Everything",
  "components": [
    { "id": "tagline", "type": "headline", "text": "Capture faster than forgetting." },
    {
      "id": "actions",
      "type": "buttonList",
      "buttons": [
        { "id": "red", "label": "Red button", "color": "#B3261E", "action": { "type": "counter" } },
        { "id": "blue", "label": "Blue button", "color": "#2563EB", "action": { "type": "counter" } }
      ]
    },
    { "id": "capture", "type": "captureBar" },
    { "id": "tasks", "type": "taskList" }
  ]
}
Publishing this Remote Config value changes the home screen for installed builds that include Firebase config. Changes are fetched at launch, through Firebase Remote Config realtime updates when available, and through a throttled foreground fallback. The client ignores destructive actions and only opens HTTPS URLs under sapientic.co. You can publish the checked-in default schema from the command line after Firebase APIs and service-account permissions are configured:
node scripts/android/publish-firebase-remote-config.mjs --service-account C:\path\to\firebase-service-account.json --file apps/android/remote-config/home-screen.json
Once Workload Identity Federation is configured, pushes to apps/android/remote-config/home-screen.json run .github/workflows/android-remote-config.yml and publish Remote Config without a Play Store build. The workflow validates the checked-in JSON before Google authentication, then publishes from a no-checkout job so the OAuth token is not exposed to repository scripts.

Versioning

CI sets:
versionCode = 1000 + github.run_number
versionName = 0.1.<github.run_number>
This keeps builds from main monotonically increasing for Google Play.