Mobile App (oxygen-alliance-app)

The flagship client. Android is live on Google Play; iOS is planned, not shipped.

Stack

  • Flutter 3.38.9, Dart SDK >=3.2.6 <4.0.0. Java 17/21, Kotlin 2.1.21, AGP 8.12, Gradle 8.13, NDK 28.2, compileSdk 36 (see README).
  • State: flutter_bloc. Routing: go_router.
  • Firebase: core, auth, storage, messaging (FCM), crashlytics, analytics; Google sign-in.
  • Media/docs: pdfrx, cached_network_image, youtube_player_iframe, file_picker, multiple_image_camera, share_plus. Local: sqflite, shared_preferences.
  • in_app_update (Android in-app updates), app_links (deep links), connectivity_plus.
  • Current version: 1.4.2+68 (pubspec.yaml).

Layout

lib/
  main.dart
  firebase.dart, firebase_options.dart, firebase_options_staging.dart
  data/           # models, repositories, data sources
  presentation/   # UI (screens/widgets)
  router/         # go_router config
  Theme/, utils/
android/, ios/, web/   # platform projects

Flavors & environments

Two Android flavors (android/app/build.gradle):

Flavor App ID Deep-link host API (--dart-define=API_URL) Firebase project
production org.bmekonza.app app.bme-konza.org https://api.bme-konza.org <PROD_FIREBASE_PROJECT>
staging org.bmekonza.app.stg <STAGING_DEEPLINK_HOST> https:// <STAGING_FIREBASE_PROJECT>

namespace is com.example.oxygen_alliance (internal) but the published applicationId is org.bmekonza.app. Firebase project/app IDs per flavor are in firebase.json — see 11-firebase.md.

Signing

  • Upload keystore: android/app/upload-keystore.jks, configured via android/key.properties (storeFile, storePassword, keyAlias, keyPassword).
  • In CI these are reconstructed from secrets UPLOAD_KEYSTORE_BASE64, STORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD (see 01-secrets-credentials (private handover docs)).
  • Google Play App Signing is enabled: you upload with the upload key, Google re-signs with the app-signing key. That's why assetlinks.json carries two fingerprints (09-website.md).

🔑 Critical to preserve: the .jks, all passwords, and the alias. Keep an offline backup. Losing the upload key requires a Google reset; losing app-signing is handled by Play but still document the current key. [TODO: where the master keystore + passwords are archived.]

Publishing (Google Play)

CI uploads via r0adkll/upload-google-play: - staging-v* → build staging flavor → upload to [TODO: internal/closed track]. - v* → build production flavor → upload AAB + mapping.txt to production track, inAppUpdatePriority: 2, status: completed.

Service accounts: STAGING_SERVICE_ACCOUNT, PROD_SERVICE_ACCOUNT (Play Console → API access → service accounts). Package org.bmekonza.app.

[TODO: Play Console account owner; review/rollout settings; data-safety form location.]

Release steps

See 03-deploy-and-releases.md. Remember to bump the +build number on every upload.

Crash reporting & analytics

Firebase Crashlytics and Firebase Analytics are integrated — see 13-monitoring-logging.md. ProGuard mapping.txt is uploaded on prod builds for deobfuscated stack traces.

iOS — planned, not shipped

The ios/ project and firebase_options*.dart include iOS app IDs, but the app is not published to the App Store. Outstanding for an iOS launch: - [ ] Apple Developer Program account + App Store Connect access ([TODO: exists?]). - [ ] iOS signing certs/provisioning profiles + CI signing. - [ ] iOS deep-link setup (Associated Domains / apple-app-site-association). - [ ] App Store listing, privacy nutrition labels, review.

Tracked in 15-known-issues-roadmap.md.