Requested: no more Android building, focus on the Docker app build and the web app. android-apk.yml also ran on every push to every branch, so every commit started an APK build beside the one workflow anyone was watching. Worse, its runner — ped-ai-android-runner — advertises the same forgejo-local label as the general runner, so it was also picking up the Docker build job and dying instantly with "'runs-on' key not defined". That is why docker-build showed a failure next to a success on the same commit. Removed: .forgejo/workflows/android-apk.yml, and the two GitHub APK workflows, which never ran at all — there is no GitHub remote on this repo, only forgejo. The Capacitor project under mobile/ is untouched and still builds by hand; docs/mobile-build.md now says plainly that nothing builds it for you. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
5.4 KiB
Mobile Build And Release
The CI build has been removed.
.forgejo/workflows/android-apk.ymland the two GitHub APK workflows are gone: CI now covers the Docker image and the web app only. The Capacitor project undermobile/is still here and still builds by hand with the Gradle commands below — nothing builds it for you.
Capacitor 6 wrapper around the hosted Ped-AI web app. The launcher defaults to https://app.pedshub.com, lets the user change the server URL, and stores that URL locally. Android is buildable on Linux. The iOS project exists but requires macOS and Xcode to produce an .ipa.
This is not a separate native clinical app. The native shell provides WebView hosting, microphone permission plumbing, secure storage, and mobile packaging for the same authenticated web app.
One-time setup
Keystore
keytool -genkeypair -v -keystore ~/pedscribe-release.jks \
-keyalg RSA -keysize 2048 -validity 10000 -alias pedscribe
Store the password in a password manager. Back up the .jks file off the
machine. Losing it = can't sign updates; Play Store requires signature
continuity (unless you're on Play App Signing).
Android Studio (optional, IDE workflow only)
export CAPACITOR_ANDROID_STUDIO_PATH="/snap/android-studio/current/bin/studio.sh"
npx cap open android
Required repo secrets (set once, via Settings → Secrets and variables → Actions
or gh secret set):
ANDROID_KEYSTORE_BASE64—base64 -w0 ~/pedscribe-release.jksANDROID_KEYSTORE_PASSWORDANDROID_KEY_ALIAS—pedscribeANDROID_KEY_PASSWORDGOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64— base64 of your Google Play service account JSON (optional). If present, the same tag build also runsbundleReleaseand uploads the AAB to Play'sinternaltrack.
Optional Play Store flow:
- Service account must have permissions to edit releases on the app in Play.
- Build task is
bundleRelease, tracked ascom.pedshub.scribe. - Upload lane is
fastlane/android publish_internal(undermobile/android/fastlane).
Tag a release:
# conventional-commits prefix auto-tags (see CONTRIBUTING.md)
git commit -m "feat: ..." && git push # auto-version workflow bumps minor
git commit -m "fix: ..." && git push # auto-version workflow bumps patch
# or force an exact version
scripts/release.sh X.Y.Z --push
APK lands on the Forgejo release. Obtainium can still track
git.danvics.com/danvics/pediatric-ai-scribe-v3 releases automatically.
Play Store upload is handled automatically for tagged builds only when
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64 is configured.
Local build (fallback / debugging)
cd mobile
npm install
npx cap sync android
cd android
./gradlew assembleRelease \
-Pandroid.injected.signing.store.file=$HOME/pedscribe-release.jks \
-Pandroid.injected.signing.store.password='<pass>' \
-Pandroid.injected.signing.key.alias=pedscribe \
-Pandroid.injected.signing.key.password='<pass>'
Output: android/app/build/outputs/apk/release/app-release.apk
For Play Store, swap assembleRelease → bundleRelease; output: .aab under
bundle/release/.
If web assets or Capacitor config changed, run npx cap sync android from mobile/ before building.
Single-quote the password
Keystore passwords with shell metacharacters (), $, !, space, etc.) must
be single-quoted. Backslash line continuations get eaten by some terminal
paste handlers — prefer one-line commands.
Reinstall on device
adb install -r android/app/build/outputs/apk/release/app-release.apk
-r keeps app data (saved server URL, auth token in Keystore, IndexedDB).
Gotchas
- JDK 17 only. Newer JDK (21/25) breaks Android Gradle Plugin. Set
org.gradle.java.home=/usr/lib/jvm/java-17-openjdk-amd64in~/.gradle/gradle.propertiesif the system default is different. - QEMU multi-arch Docker builds fail with SIGILL on native modules (argon2). Docker Hub workflow is x86-only. Use a native ARM runner if you need ARM64.
npx capmust run insidemobile/, not repo root.- Foreground recording on Android 14+ requires
foregroundServiceType="microphone"inAndroidManifest.xmlplus the 3-argstartForeground(id, notif, TYPE_MICROPHONE). Already applied. - Mic "denied" after permission grant — WebView intercepts the prompt. Fix: long-press app icon → App info → Permissions → Microphone → Allow.
Files
Note on com.pedshub.scribe: that's the Android applicationId — the OS-level
unique identifier for this app. Chosen by reverse-DNS of pedshub.com. It is
not a reference to the separate PedsHub Quiz app; they share a prefix by
coincidence. Don't rename it — Android treats applicationId as the primary
key; renaming breaks Play Store update continuity and forces every installed
user to uninstall + reinstall.
| Path | Purpose |
|---|---|
mobile/capacitor.config.json |
appId, name, WebView config, plugin opts |
mobile/src/ |
launcher HTML and server URL entry, defaulting to https://app.pedshub.com |
mobile/android/app/src/main/java/com/pedshub/scribe/MainActivity.java |
JS bridge + WebView mic permission |
mobile/android/app/src/main/java/com/pedshub/scribe/AudioRecordingService.java |
foreground service for background recording |
mobile/android/app/src/main/AndroidManifest.xml |
permissions, intents, backup rules |
mobile/android/fastlane/Fastfile |
internal Play track upload lane |