Building the Android App
5 min read
This guide builds the Android version of the Academy & Exam OS student app for your institute. Complete Flutter Mobile App — Setup & Configuration first: you need a validated production profile (config/production.local.json).
Prerequisites:
- Flutter 3.44.x with Dart 3.12, and
flutter doctorshowing a working Android toolchain; - the Android SDK with the API 36 platform and build tools, and JDK 17 or newer;
- a validated production profile;
- a Google Play developer account if you will publish on Google Play.
Run every command from the Flutter-App-Source/ folder.
Step 1: Set the application ID, name and icon #
- Application ID: set
ANDROID_APPLICATION_IDin the profile (reverse-DNS, for exampleorg.myinstitute.learn). If it is not set, release builds usecom.osdots.academyexam. Choose your own ID before the first store upload — it cannot change afterwards. Debug builds always append.dev, so a development install never replaces a release install. - App name: the launcher label is
SITE_NAMEfrom the profile. - Icon: replace the launcher icons in
android/app/src/main/res/mipmap-*/ic_launcher.pngwith your institute’s icon. The shipped icons are neutral placeholders.
Step 2: Create your upload key #
Release builds must be signed with your own upload key; the Android debug key is refused. Create a keystore once:
keytool -genkeypair -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias uploadThen create android/key.properties with the location and passwords of your keystore:
storeFile=/absolute/path/to/upload-keystore.jks
storePassword=<store password>
keyAlias=upload
keyPassword=<key password>Important: Keep the keystore and its passwords private and backed up. If you lose them, you cannot publish updates to the same app on Google Play. Never share or commit
android/key.properties.
Step 3: Build the release #
Build an Android App Bundle for Google Play:
flutter build appbundle --release --dart-define-from-file=config/production.local.jsonThe bundle is written to build/app/outputs/bundle/release/app-release.aab.
For a directly installable test build with the same configuration, build an APK:
flutter build apk --release --dart-define-from-file=config/production.local.jsonThe release gate #
The Android project refuses to build a release unless:
android/key.propertiesnames an existing keystore with all four values; and- the build received a production profile that passes validation (the validator runs automatically inside the Gradle build).
A build without a profile, with a development profile or with the unedited template stops and prints the reason. Debug and profile builds are not gated; they are for development and label themselves on screen.
Step 4: Verify on a device #
- Install the APK on a test device (for example
adb install app-release.apk), or share the build through Google Play’s internal testing track. - Open the app.
Expected result: the app shows your institute name, loads the published test catalogue from your website over HTTPS, and lets students sign in with their website accounts.
- “Cannot reach …” — the device cannot reach
API_BASE_URL. - “This app does not match the configured institute” —
DEPLOYMENT_IDorBRAND_KEYbelongs to another installation.
Step 5: Publish on Google Play #
Upload app-release.aab in the Google Play Console under your own developer account and complete the store listing, content rating and data-safety information there. Google’s review, fees and policies apply to your account; they are not part of Academy & Exam OS.
When your listing is live, add its address under Mobile / App Store Settings on your website so the homepage app showcase shows the Google Play button. See Website & CMS.
Troubleshooting #
| Symptom | Cause and fix |
|---|---|
Release builds need android/key.properties … | Create the signing configuration of Step 2. The debug keystore and the alias androiddebugkey are refused. |
Release builds require a validated production profile … | Pass --dart-define-from-file=config/production.local.json. |
The production profile did not validate: followed by codes | Fix the listed keys; run dart run bin/validate_profile.dart config/production.local.json to check quickly. |
[api_host] | The host is an IP address, a single word or a reserved / local / example name (.local, .test, .example, localhost …). Use your institute’s real HTTPS domain. |
[deployment_id] | The value is not the UUID your website reports, or is still the template placeholder. |
| App shows This app does not match the configured institute | DEPLOYMENT_ID or BRAND_KEY differs from your website’s /api/v1/bootstrap answer. Rebuild with the right values. |
| App shows Cannot reach … or A secure connection could not be verified | The device cannot reach API_BASE_URL, or your website’s TLS certificate is not trusted by the device. Self-signed certificates are never accepted. |
| App shows This build is not configured for release | A release build was produced without a valid profile (only possible when the build gate was bypassed). Rebuild through the gate. |
Gradle on Windows: Could not close incremental caches … different roots | The project and the pub cache are on different drives. Keep the project on the drive of the pub cache (or set PUB_CACHE to a folder on the project’s drive) and rebuild. |
Unable to open file … hook.dill for writing snapshot on the first build | A file-locking tool such as an antivirus scanner held a new file. Run the same command again. |
| Google button missing | One of the Google sign-in conditions is not met. See the Google section in Flutter Mobile App — Setup & Configuration. |
Related documents #
Watch the Video Tutorial #
This topic is also covered in Academy & Exam OS Video Tutorial 11: Flutter App Setup & Android Build (watch on YouTube). All Academy & Exam OS video tutorials.