Android
Requirements
Section titled “Requirements”- Android SDK with platform tools (ADB)
- An Android emulator or connected device
- Flutter app built with
--dart-define=PROBE_AGENT=true
Emulator Setup
Section titled “Emulator Setup”List available devices
Section titled “List available devices”probe device listStart an emulator
Section titled “Start an emulator”probe device start --platform androidOr start manually:
emulator -avd Pixel_7_API_34 -no-snapshot-loadBuild and install your app
Section titled “Build and install your app”flutter build apk --debug --dart-define=PROBE_AGENT=trueadb install -r build/app/outputs/flutter-apk/app-debug.apkadb shell am start -n com.example.myapp/.MainActivityConnection Flow
Section titled “Connection Flow”- The CLI runs
adb forward tcp:<host-port> tcp:<device-port>to bridge the emulator network - The CLI connects via WebSocket to
ws://127.0.0.1:<host-port>/probe?token=... - The auth token is extracted from
adb logcatoutput matchingPROBE_TOKEN= - Once authenticated, the CLI dispatches JSON-RPC commands to the Dart agent
By default, both host and device ports are 48686. For parallel testing, set different host ports per device.
Port Forwarding
Section titled “Port Forwarding”agent: port: 48686 # host-side port device_port: 48686 # on-device port (what ProbeAgent listens on)For parallel testing with multiple devices:
agent: port: 48687 device_port: 48686This maps adb forward tcp:48687 tcp:48686, keeping the device port the same while using a unique host port.
Custom ADB Path
Section titled “Custom ADB Path”If ADB is not on your PATH:
probe test tests/ --adb /path/to/platform-tools/adbOr in probe.yaml:
tools: adb: /path/to/platform-tools/adbPermissions
Section titled “Permissions”Android runtime permissions are granted via adb shell pm grant:
allow permission "camera" # adb shell pm grant <pkg> android.permission.CAMERAdeny permission "location" # adb shell pm revoke <pkg> android.permission.ACCESS_FINE_LOCATIONgrant all permissions # grants all known runtime permissionsAvailable permissions: notifications, camera, location, microphone, storage, contacts, phone, calendar, sms, bluetooth.
Native UI Automation
Section titled “Native UI Automation”Android is currently the only platform where probe can reach outside the Flutter widget tree
into native, OS-owned UI — pickers, share sheets, and any other surface the Dart agent can never
see. Elements are matched against uiautomator’s text or resource-id and driven via
uiautomator dump + input tap/input text — no new dependencies, adb already ships both:
tap native "Choose from Gallery"see native "IMG_0001.jpg"don't see native "Error"type native "wifi" into "Search settings"Notes from real-device verification:
- Matching is a case-insensitive substring against both
textandresource-id. - If the native element is reached via a screen transition, add a
waitstep first — the same idiom used after Flutter navigation. take a screenshot(the Dart-agent verb) cannot capture native UI — it renders only Flutter’s own tree. Useadb exec-out screencapexternally to visually verify native state.- API 35 pitfall for your own native screens: forced edge-to-edge can place a top-of-screen
element’s reported bounds center underneath the app bar, which silently eats the tap — handle
window insets (
fitsSystemWindowsor equivalent).
A purpose-built native fixture app with stable ids lives in the repo under native-test-apps/.
Device Media
Section titled “Device Media”add media "fixtures/photo.jpg" # adb push + MEDIA_SCANNER_SCAN_FILE broadcastThe file lands in /sdcard/Pictures/ and is MediaStore-indexed, so it is genuinely visible to
image pickers — combine with the native UI verbs above to actually select it.
Deep Links
Section titled “Deep Links”open link "myapp://profile/42" in the appDispatches am start -a android.intent.action.VIEW, so a custom scheme or App Links URL
registered by your app is delivered to the app itself — including cold-launching it from fully
terminated (unlike iOS Simulator; see the iOS page). Plain open link "https://..." (no suffix)
still opens the external browser via url_launcher.
Location
Section titled “Location”set location 48.1351, 11.5820 # adb emu geo fix (emulators only)Simulate movement through an ordered route with travel to — interpolates between waypoints and
calls the same adb emu geo fix primitive repeatedly at ~1-second intervals, rather than jumping
instantly:
travel to 48.1351, 11.5820 48.1451, 11.5920over 10 secondsVideo Recording
Section titled “Video Recording”Android uses the built-in screenrecord command. Videos are recorded as MP4 (H.264). The CLI auto-chains recordings to work around the 180-second limit.
probe test tests/ --video --video-resolution 720x1280 --video-framerate 2If scrcpy is installed, it is used as the preferred backend for higher quality recordings.
If ffmpeg is installed, multi-segment recordings are stitched into a single file. Without it, segments are kept as separate files.
Configuration
Section titled “Configuration”device: emulator_boot_timeout: 120s boot_poll_interval: 2s token_file_retries: 5 restart_delay: 500ms
agent: port: 48686 dial_timeout: 30s ping_interval: 5s token_read_timeout: 30s reconnect_delay: 2s