Skip to content

feat(dart): Flutter on an Android emulator, measured end to end (#790, M3) - #883

Merged
debugmcpdev merged 2 commits into
mainfrom
feat/790-m3-android
Oct 9, 2026
Merged

debugmcpdev merged 2 commits into
mainfrom
feat/790-m3-android

Conversation

@debugmcpdev

Copy link
Copy Markdown
Collaborator

Part of #790 — M3 of three (Android emulators and devices), the "pass the device to use" half of the request. M1 (#880) wired deviceId → flutter run -d <id>; M2 (#881) proved desktop and tests; this proves the emulator through the server and pins it.

What this adds

  • tests/e2e/mcp-server-smoke-flutter-android.test.ts — two cases measured through dist/index.js on Windows (Flutter 3.47.7, AVD mcp_api35 booted headless, Gradle warm, the debug APK installed up front):

    Case Warm
    flutter run -d emulator-5554, breakpoint in build(): _ProbeAppState.build, counter → 0, continue keeps it running, close_debug_session terminates the app 20 s
    integration_test on the emulator: the test's breakpoint, then the test's tap hits the app's increment() breakpoint, ✓ device increment, stopped end 21.6 s

    The opt-in is a booted emulator (flutter emulators --launch <id>); the suite self-skips without Flutter, adb or an online emulator, and with MCP_SKIP_FLUTTER_ANDROID=1. It never runs on CI.

  • e2e helpers — adb discovery (ANDROID_SDK_ROOT/ANDROID_HOME/PATH), the online-emulator gate (adb devices says device, and flutter devices lists it), prepareFlutterAndroid (flutter create --platforms=android, one flutter build apk --debug, adb install -r -t) and resetAndroidApp (am force-stop + adb forward --remove-all before every launch). Both steps come from measurements: the first flutter run after a fresh APK install once ended without a stop, and the spike saw a launch hang while a live instance was being replaced.

  • Docs — the guide's Android section with the numbers and the recipe, KNOWN_ISSUES (attaching to an app another flutter run started on the emulator does not connect, tracked in dart: attaching to an app another flutter run started on an Android emulator never connects (host-forwarded VM-service URI) #882; stop the previous instance first), the spike notes' M3 table, the e2e README, the changelog fragment.

No adapter or core code changes.

Measured but deferred

With this merged, #790's three milestones are on main; the announcement checklist is next.

🤖 Generated with Claude Code

M3 of #790. `deviceId: "emulator-5554"` already reached `flutter run -d`
through M1's wiring; this proves it through the server and pins it:

- tests/e2e/mcp-server-smoke-flutter-android.test.ts: `flutter run` on the
  emulator with a breakpoint in build() (widget state, continue keeps it
  running, close terminates the app) and an integration_test on the
  emulator whose tap hits the app's breakpoint. Opt-in by booting an
  emulator; self-skips without Flutter, adb or an online emulator, and
  with MCP_SKIP_FLUTTER_ANDROID=1. Never runs on CI.
- tests/e2e/dart-example-utils.ts: adb discovery, the online-emulator
  gate, prepareFlutterAndroid (flutter create --platforms=android, one
  debug APK build, adb install -r -t) and resetAndroidApp (force-stop +
  forward --remove-all before every launch). Measured: the first run
  after a fresh install once ended without a stop; the next was fine.
- Docs: the guide's Android numbers (build() breakpoint ~21 s,
  integration_test ~28 s warm; a cold Gradle build is minutes and belongs
  to the first build), KNOWN_ISSUES (emulator attach does not connect,
  #882; stop the previous instance first), the spike notes' M3 table,
  the e2e README, the changelog fragment.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…es not already do (#790)

From the scoped review of #883:

- `adb forward --remove-all` is host-wide (killforward-all drops every
  device's listeners), so it took other tools' forwards with it. The helper
  now removes only this emulator's entries from `adb forward --list`.
- `flutter run` force-stops, builds and installs on every launch
  (android_device.dart startApp → stopApp, installApp), and
  `flutter build apk --debug` builds three ABIs while `flutter run` builds
  the device's, so the warm-up used to be replaced by the first launch.
  The prebuild now targets the device's ABI (ro.product.cpu.abi); the
  docstring, guide, KNOWN_ISSUES and spike notes say what it buys — a warm
  Gradle cache and the first install — instead of describing it as a fix,
  and the once-seen "ended without a stop" is labelled as seen once.
- `adb` errors now carry stderr (install failures report their reason),
  and an incompatible installed APK is uninstalled once and retried, the
  way flutter_tools does.
- adb discovery covers Android Studio's default SDK paths on macOS and
  Linux; the emulator gate consults Flutter's device list before starting
  an adb server.
- Both Flutter suites wait for a stop in `wait_for_stop` slices of at most
  45 s: the MCP client caps a request at 60 s, and one long server-side
  wait failed on the client side when a build kept the first stop away
  for 63 s (seen on the emulator's integration case).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@debugmcpdev
debugmcpdev merged commit e44f1fe into main Oct 9, 2026
14 checks passed
@debugmcpdev
debugmcpdev deleted the feat/790-m3-android branch October 9, 2026 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants