Troupeby AliveDocsSign in

Platforms

Android Emulator

Troupe runs your app on Android Emulators that it creates, boots and deletes itself. This page covers what your machine needs, how Troupe drives an emulator, and what the platform can and cannot do.

The platform's id is android-emulator. A troupe.config.ts may write android.

Requirements

  • macOS on Apple silicon. Linux on x86-64 with KVM is planned for Android and is not verified yet.
  • An Android SDK with the emulator and platform-tools packages and a system image for the host's architecture: arm64-v8a on Apple silicon.
  • Bun 1.4.3 or newer.
  • Memory for each emulator: the guest gets 4096 MB by default, and Troupe budgets 3,900 MB more for the emulator around it.

Install a system image with the SDK's own tool:

Shell
sdkmanager "system-images;android-36;google_apis;arm64-v8a"

Prepare the platform

Run this once in your project:

Shell
bunx troupe install android

It looks for your SDK in ANDROID_HOME, then ANDROID_SDK_ROOT, then ~/Library/Android/sdk, and records the one it finds in ~/.troupe/host.json. From then on the runtime reads only the recorded path, never the environment of the command that started it. It then runs the environment checks and starts one emulator to prove the path. There is nothing to build: the driver ships with the platform package.

A project then names the device and the app:

TypeScript
import { defineConfig } from '@alivelabs/troupe'

export default defineConfig({
  projects: [
    {
      name: 'android',
      use: { platform: 'android', deviceType: 'Pixel 8', os: '36', app: './build/shop.apk' },
    },
  ],
})

How Troupe drives an emulator

Troupe owns each part: it does not depend on Appium, UiAutomator2 server builds or another driver.

PartWhat it does
Troupe's adb clientSpeaks the adb server's wire protocol itself: installs and launches apps, runs shell commands, reads logcat
The emulatorTroupe writes its own AVDs into $TROUPE_HOME/avd and boots them with the SDK's emulator
The instrumentation driverTwo APKs Troupe installs on the emulator. They read the accessibility tree, resolve locators and perform test actions
scrcpyThe scrcpy server, version 4.0, captures the screen as H.264 for the live stream and delivers live input

Devices are Troupe's own

Troupe names its AVDs troupe-… and acts only on an emulator whose console confirms it runs one of them. A phone you have plugged in, or an emulator you started from Android Studio, is never touched.

Troupe uses the adb server that already runs on your machine. When none runs, it starts one with the SDK's adb and leaves it running. It never stops or restarts a server that is already running.

Emulators take console and adb ports in adb's usual window, 5554 to 5584. The driver is reached through the adb connection, so it needs no forwarded port.

Apps

Troupe installs .apk files. An Android App Bundle (.aab) is not installable: build an APK from it first. An APK built for another architecture is refused with APP_INSTALL_FAILED and the reason wrong-arch.

Android apps have no process arguments or environment. Launch arguments reach the app as the string-array intent extra troupe.args, and each launch environment variable as the string extra troupe.env.<NAME>.

Clearing an app's data and deep links both work.

Capabilities

The runtime reports these through runtime.capabilities, and refuses a call the platform cannot serve with CAPABILITY_UNSUPPORTED before it touches the device.

AreaAndroid Emulator
LocatorsRole, text, label, placeholder and test id, with regular expressions; system UI through screen.system
Test idresource-id (React Native's testID)
TouchUp to ten contacts: tap, double tap, long press, swipe, drag, pinch, scroll, gestures
KeyboardKey events and text
Hardware buttonshome, back, appSwitch, power, volumeUp, volumeDown
Rotation, hiding the keyboardYes
Permissionscalendar, camera, contacts, location, locationAlways, microphone, motion, notifications, photos
System settingsLocation and appearance
ScreenshotsYes
Live streamH.264
Live inputThe same touch, keys, buttons and rotation as tests
LogsSystem log, app log and crash reports
Screen recordingNo

Limits

  • A Jetpack Compose node has a test id only when the app sets testTagsAsResourceId.
  • The clipboard cannot be read or written: system.getClipboard and system.setClipboard are refused.
  • The permission reminders is not offered.
  • The stream does not take frame-rate or bitrate changes while it runs.
  • Foldable device types are not offered.

Device types and OS versions

Troupe offers four device types:

deviceTypeNameScreen
pixel_8Pixel 8 (the default)1080 × 2400 px at 420 dpi
pixel_9Pixel 91080 × 2424 px at 420 dpi
medium_phoneMedium Phone1080 × 2400 px at 420 dpi
pixel_tabletPixel Tablet2560 × 1600 px at 320 dpi

A spec may name one by id or by name.

  • os is the API level as a string, such as '36'. Without one, or with 'latest', Troupe takes the newest installed image.
  • variant is the system image's tag. The default is google_apis. Name another installed tag, such as google_apis_playstore, to use it.

Troupe lists the images installed in your SDK for the host's architecture. An image that is not installed fails with ENVIRONMENT_ANDROID_IMAGE_MISSING. Its fix is the sdkmanager command that installs it.

List what a runtime offers with catalog.deviceTypes and catalog.osVersions:

TypeScript
const { osVersions } = await troupe.call('catalog.osVersions', { platform: 'android-emulator' })

Host settings

troupe install android writes platforms.android-emulator in $TROUPE_HOME/host.json. You can edit these keys:

KeyDefaultWhat it does
sdkRootThe SDK troupe install android foundThe Android SDK Troupe uses
maxDevices2The most emulators running at once
memoryMb4096The guest's memory
enabledtruefalse switches the platform off: a request for it fails with ENVIRONMENT_PLATFORM_DISABLED

Next

esc

    Type to search every page, the protocol reference and the cloud API.