Skip to content

0014 — Android app delivery ​

Status: Accepted (2026-06-18 — owner accepted during ADR review)

Date: 2026-06-17

ADO work item: AB#3139

Deciders: Kristopher Turner (platform owner)


Context ​

ADR 0002 establishes that both iOS and Android are delivered from a single React Native + Expo (apps/mobile) codebase built with EAS Build. The iOS delivery path is addressed in ADR 0009. This ADR covers the Android-specific delta on top of the already-proven shared Expo app: the configuration, pipelines, and platform decisions that are unique to the Android surface.

Because the codebase is shared, the work here is not a second implementation — it is completing the Android side of what the iOS delivery already exercised, plus the one area that iOS cannot inform: the Google Play ecosystem.

The Android delivery comprises five concerns:

  1. Firebase Cloud Messaging (FCM) push — the Android counterpart to iOS APNs; wires into the same platform notifications transport (ADR 0008, responsibility 4) rather than a parallel channel. The shared apps/mobile notification surface must behave identically on both platforms; only the underlying provider (APNs vs. FCM) differs.

  2. EAS Build → Google Play release pipeline and signing — an Android App Bundle (AAB) built by EAS Build, signed with a platform-managed keystore, and promoted through Google Play's internal → production track via EAS Submit or the Play Developer API. The iOS EAS pipeline already exists; this is the Android lane of the same eas.json configuration.

  3. Clerk Google Sign-In on Android — ADR 0003 records a concrete open risk: whether Clerk's Expo SDK wraps @react-native-google-signin/google-signin natively on Android was not confirmed in Phase-0 research. This must be resolved before this phase ships. If Clerk does not handle native Android Google Sign-In, a @react-native-google-signin integration alongside Clerk is required. Either path is acceptable; the unverified state is not.

  4. Google Play Data safety form + COPPA/Families policy — Google Play requires a completed Data safety declaration (data collected, data shared, security practices) and enforces the Families policy for apps with content directed at children. Heritage Community Hub admits child sub-accounts (parent-managed, no email, no Clerk identity — ADR 0007). This creates an obligation to evaluate whether the app triggers the Families policy (full or partial compliance), complete the Data safety form accurately, and confirm that FCM, Clerk, and any analytics SDKs included in the Android build are disclosed.

  5. Offline cache/sync parity — ADR 0002 designates offline cache/sync a Phase 4 requirement on both platforms. The Android build must reach the same offline baseline as iOS, using the same api-client caching layer rather than a platform-specific solution.

This ADR is a planning/architecture document. It introduces no code. Implementation is Epic AB#3139 (Features: AB#3147 Android EAS build, AB#3148 FCM push, AB#3149 Google Play publish). Android is sequenced after iOS in the roadmap (Phase 6) so the shared app is proven on one store before the second store lane is opened.

Decision ​

We will deliver the Android app by configuring the EAS Build Android lane in the shared apps/mobile codebase, wiring FCM push into the existing platform notifications transport, verifying and completing the Clerk native Google Sign-In path before release, satisfying the Google Play Data safety and Families policy obligations for child-bearing apps, and matching the iOS offline cache/sync baseline — with no separate Android codebase or repo.

Android delivery map ​

text
  apps/mobile (shared React Native + Expo)

  ├── Notifications
  │   ├── iOS  → APNs (ADR 0009)
  │   └── Android → FCM  ← this ADR
  │       └── both route through platform notifications transport (ADR 0008 §4)

  ├── Auth
  │   ├── iOS  → Sign in with Apple (verified, Clerk Expo SDK)
  │   └── Android → Google Sign-In  ← must verify Clerk Expo SDK coverage
  │       └── fallback: @react-native-google-signin + Clerk token exchange

  ├── EAS Build
  │   ├── iOS lane  → .ipa → App Store Connect → App Store  (ADR 0009)
  │   └── Android lane → .aab → Google Play (internal → production)  ← this ADR
  │       └── keystore managed via EAS credentials store

  └── Offline cache/sync
      └── shared api-client layer; Android must reach iOS parity (Phase 6)

Phase-6 delivery sequence ​

  1. Verify Clerk Google Sign-In native path on Android (EAS dev build). Document outcome — either confirm the Clerk Expo SDK handles it, or integrate @react-native-google-signin alongside Clerk.
  2. Add FCM to the Expo config plugin (app.json/app.config.js); wire FCM token registration and notification handlers into the existing api-client + platform notifications transport.
  3. Configure the EAS Build Android lane (eas.json profile: development / preview / production); generate the Android keystore via EAS credentials; confirm signing round-trip.
  4. Complete the Google Play Data safety form; assess Families policy applicability; add required disclosures for FCM and Clerk.
  5. Validate offline cache/sync parity against the iOS baseline.
  6. Submit AAB via EAS Submit to the Google Play internal track; promote to production after staged rollout review.

Alternatives considered ​

OptionProsConsWhy not chosen
EAS Build Android lane in shared Expo codebase (chosen)One codebase; reuses shared-types, api-client, ui packages; EAS Submit automates Play publish; iOS proof already existsEAS Build is not free above the free tier; Play review adds 1–3 day latency— chosen
Native Kotlin app (separate codebase)Best-in-class Android UX ceiling; full platform API accessDuplicates all business logic; breaks the one-codebase model of ADR 0002; requires Kotlin skills separate from the TypeScript teamDirectly contradicts ADR 0002
Android-only PWA (no Play Store app)No app store review; instant deployNo FCM push (Web Push on Android is fragile); weak offline; no Play Store presence; does not satisfy closed-community install controlOffline and push are non-negotiable (ADR 0002); no Play presence reduces discoverability and trust
Capacitor (web wrapper, Android target)Reuses web codebase; no RN knowledge neededLimited native module access; push and offline are harder to guarantee; would split the app surface from the iOS RN+Expo appA separate mobile technology for Android contradicts the shared-codebase decision
Separate Android repo (shared logic as npm packages)Explicit release boundaryAll shared code must be versioned and published as packages; adds publish/version overhead; the release pipeline is already the only defensible split pointThe only split that makes sense is the EAS Build lane, not a separate repository

Consequences ​

Positive ​

  • A single apps/mobile PR that fixes or extends behavior ships to both iOS and Android via their respective EAS lanes — no divergent implementations of the same feature.
  • FCM wires into the same platform notifications transport as APNs; the platform owns the notification API contract (ADR 0008 §4); the mobile app remains a thin client.
  • EAS credentials store manages the Android keystore centrally — no local keystore files, no secrets in source control.
  • The Clerk Google Sign-In verification in this phase closes the open risk recorded in ADR 0003 and ADR 0002, giving the platform a confirmed auth baseline for both platforms.
  • Google Play's managed distribution model (internal track staging, staged rollouts) improves the release safety story relative to side-loading.

Negative / trade-offs ​

  • Android follows iOS in the roadmap (Phase 6) — the community does not have an Android app until at least Phase 6. This is a deliberate sequencing choice, not a gap.
  • EAS Build has a free tier (limited concurrent builds, limited build minutes). If build frequency exceeds free-tier limits, a paid EAS plan is required. Monitor and plan for this as release cadence increases.
  • Google Play's review process (1–3 days typical; up to 7 days for new apps) adds latency to the first publish and to any release that changes the app's declared data practices.
  • The Families policy assessment may require changes to the app's content rating, data disclosures, or SDK choices depending on how Google classifies a community app with child sub-accounts. This must be resolved before first submission, not after.

Risks ​

  • Clerk native Google Sign-In on Android (open, must resolve in Phase 6) — the exact native Google Sign-In integration for Expo + Clerk was not verified in Phase-0. If Clerk's Expo SDK does not handle the Android native path, a @react-native-google-signin + Clerk token-exchange integration is required. This is solvable but adds development effort. Mitigation: spike this first in Phase 6, before FCM or Play pipeline work begins.
  • Google Play Families policy — if Google determines the app is directed at children (given the family-group and child sub-account model), the Families policy requires additional compliance steps (restricted ad SDKs, content rating, parental consent UI). Mitigation: complete the Data safety assessment early; consult the Families policy guidance before submitting.
  • Keystore loss — losing the Android release keystore permanently locks the app out of Play Store updates for that package name. Mitigation: EAS credentials store is the primary backup; export and store the keystore separately in Key Vault (kv-hcs-vault-01) before first production submission.
  • EAS Build managed workflow limits — some Android-specific native customizations may require ejecting to the bare workflow. Mitigation: evaluate Expo's config plugin system for each native requirement before Phase 6; document any eject trigger in the relevant ADR.
  • FCM token lifecycle — FCM tokens rotate; stale tokens cause silent push failures. Mitigation: the platform notifications transport (ADR 0008 §4) must implement token refresh and delivery-failure handling at the API layer, not in the mobile client.

References ​

Heritage Community Hub — Internal. Access restricted via Cloudflare Access + Entra ID.