Android
Android emulator, end to end with the automation
No physical phone needed: the Android harnesses (appium_run_android.sh,
verify_all_modules.sh, capture_run.sh, the demo.sh demos) treat an emulator
exactly like a device, they resolve whatever adb reports in state device,
including an emulator-5554.
Install the emulator package and a system image (once):
Create an AVD from that image:
Boot it headless (no window) and wait until it’s fully ready:
Confirm adb sees it, then run any harness, it auto-selects the emulator:
sdkmanager/avdmanager/emulatorship with the Android SDK cmdline-tools; if they’re not onPATH, they live under$ANDROID_HOME/cmdline-tools/latest/binand$ANDROID_HOME/emulator. SetANDROID_HOME/JAVA_HOMEonce (see Prerequisites → environment variables) so the manualadb/emulatorcommands resolve, the harness scripts above auto-resolve both, so they work even if your shell profile doesn’t set them. Use an x86_64 system image on Intel hosts.
Install on a physical device, clone → build → adb install
End-to-end, from a fresh clone to the app running on a plugged-in Android
phone. (flutter build apk drives Gradle/gradlew under the hood and
injects the DVMA flavor via --dart-define-from-file, so it’s the correct
entry point, see the note on gradlew
below.)
Prereqs:
flutter doctoris green for Android, and the phone has USB debugging on (Settings ▸ Developer options ▸ USB debugging) and is authorized. Clone and generate.Confirm the device is visible.
Install to the device. Either build and install in one step…
…or build the APK, then install it explicitly with
adb.Launch it (or just tap the DVMA icon).
The APK lands at build/app/outputs/flutter-apk/app-release.apk
(app-debug.apk for a debug build). The release build type is signed with
the debug keystore (see android/app/build.gradle.kts), so it installs on
any device with no extra signing setup, this is intentional for a local
training target, not a store-ready build.
Debug APK (faster iteration, debuggable, Frida-friendly)
For hands-on work you often want the debug build instead of release: it’s
quicker to produce, ships with android:debuggable="true" (so you can attach a
debugger / run-as the app), and is the natural target for dynamic-analysis
exercises (Frida, objection). Same flavor flag, just --debug:
Notes:
- Debug builds run in JIT mode and are larger/slower at runtime than
release; use release when you’re measuring performance or testing
release-only behavior (e.g. R8/obfuscation,
--split-debug-info). flutter run --dart-define-from-file=config/flavors/dev.jsonis effectively a debug build with hot reload attached, the fastest loop while developing.- Both debug and release install side-by-side is not possible here (same
applicationId);adb install -rreinstalls over the other.
Building the APK with gradlew directly (advanced)
DVMA’s flavors are --dart-define compile-time configs, not Gradle product
flavors. A bare ./gradlew assembleRelease therefore builds an APK without
the DVMA flavor wiring (it falls back to the built-in default), because Gradle
never sees the dart-defines. flutter build apk is the supported way to inject
them, so prefer it, it drives gradlew for you.
If you specifically need the underlying Gradle command (e.g. to plug into an existing CI pipeline), let Flutter print it and copy it verbatim rather than hand-encoding the defines:
(The -Pdart-defines value is a Flutter-internal base64 encoding of each
key=value, which is why hand-rolling it is fragile and flutter build apk /
flutter install are the recommended path.)