pediatric-ai-scribe-v3/docs/mobile-build.md
2026-05-09 00:40:45 +02:00

4.7 KiB

Mobile Build And Release

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

CI build (preferred)

Tag-triggered. Push any vX.Y.Z tag → .github/workflows/android-release.yml builds a signed APK on a GitHub runner and attaches it to the matching release.

Required repo secrets (set once, via Settings → Secrets and variables → Actions or gh secret set):

  • ANDROID_KEYSTORE_BASE64base64 -w0 ~/pedscribe-release.jks
  • ANDROID_KEYSTORE_PASSWORD
  • ANDROID_KEY_ALIASpedscribe
  • ANDROID_KEY_PASSWORD

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 at the GitHub release; /releases/latest link in the login page resolves to it automatically. Obtanium subscribers (github.com/<owner>/<repo>) pick up the update on next poll.

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 assembleReleasebundleRelease; 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-amd64 in ~/.gradle/gradle.properties if 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 cap must run inside mobile/, not repo root.
  • Foreground recording on Android 14+ requires foregroundServiceType="microphone" in AndroidManifest.xml plus the 3-arg startForeground(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
.github/workflows/android-release.yml CI build