Test Android apps
Set up Appium and adb, then run your tests on an Android phone or emulator.
Optics drives Android apps through Appium, an open-source server that taps, types and reads the screen on a device. You run the Appium server on your machine, Optics talks to it, and Appium talks to the phone or emulator over adb (Android Debug Bridge, the SDK's device tool).
This page uses Birch, a sample shoe store app with the package name com.birch.shop. Replace it with your own app.
Before you begin#
You need:
- Optics installed. See Install Optics.
- Node.js 20 or newer, to run the Appium server.
- The Android SDK. We recommend getting it with Android Studio, which also creates emulators.
- An emulator, or an Android phone and a USB cable.
Set up#
Install the Appium engine#
$ optics setup --install appiumThis adds the Python client that Optics uses to talk to Appium. It doesn't install the server.
Install the Appium server and its Android driver#
$ npm install -g appium $ appium driver install uiautomator2UiAutomator2 is the Appium driver for Android. It needs the
ANDROID_HOMEenvironment variable set to your SDK folder, and Java installed. Runappium driver doctor uiautomator2to check both.Make adb available#
adb ships in the SDK's
platform-toolsfolder. Add that folder to your PATH, then check it:$ adb versionOn macOS the SDK is usually in
~/Library/Android/sdk, on Linux in~/Android/Sdk, and on Windows in%LOCALAPPDATA%\Android\Sdk.Start an emulator or connect a phone#
For an emulator, open Android Studio's Device Manager and start a virtual device.
For a phone, turn on Developer options (tap Build number seven times in Settings > About phone), then turn on USB debugging. Connect the cable and accept the "Allow USB debugging?" prompt on the phone.
Check that adb sees it:
$ adb devices List of devices attached emulator-5554 deviceThe first column is the device's serial.
devicein the second column means it's ready.unauthorizedmeans you still need to accept the prompt on the phone.Find the app's package and activity#
Optics needs the app's package (its id, such as
com.birch.shop) and its activity (the screen it opens on). Open the app on the device, then ask adb what has focus:$ adb shell dumpsys window | grep -E 'mCurrentFocus' mCurrentFocus=Window{4f2a1c u0 com.birch.shop/com.birch.shop.MainActivity}The part before the
/is the package, and the part after it is the activity. If you know the package, you can also ask Android for its launch activity:$ adb shell cmd package resolve-activity --brief com.birch.shop priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=true com.birch.shop/.MainActivityAn activity that starts with a dot is short for the package plus that name:
.MainActivitymeanscom.birch.shop.MainActivity.Write config.yaml#
Create a project with
optics init birch-android, then replace itsconfig.yaml:config.yaml driver_sources: - appium: enabled: true url: "http://127.0.0.1:4723" # where the Appium server listens capabilities: # must not be empty platformName: Android # required; picks the Android setup automationName: UiAutomator2 deviceName: emulator-5554 udid: emulator-5554 # optional; pins one device appPackage: com.birch.shop # app opened by "Launch App" with no value appActivity: com.birch.shop.MainActivity # appium:settings: {allowInvisibleElements: true} # optional; include off-screen elements elements_sources: - appium_find_element: {enabled: true} # asks Appium for XPaths, ids and text - appium_page_source: {enabled: true} # searches the app's UI tree - appium_screenshot: {enabled: true} # screenshots for OCR and image matching text_detection: - easyocr: {enabled: true} # needs: optics setup --install easyocr image_detection: - templatematch: {enabled: true} # finds .png templates anywhere in the project log_level: INFO file_log: true json_log: trueAlways set
url. Optics can't connect if it's missing or empty. If you don't need OCR yet, delete thetext_detectionblock, because an enabled OCR engine must be installed for every run.Check the setup#
$ optics doctor birch-androidMobile ✅ adb found at /Users/you/Library/Android/sdk/platform-tools/adb ✅ adb devices 1 connected: emulator-5554 ⚠️ appium server not reachable at 127.0.0.1:4723 → Start it in another terminal with the `appium` command. Project ✅ config: driver appium enabled ✅ config: appium element source enabled: appium_find_element, appium_page_source, appium_screenshot ✅ config: appium settings required settings presentFix every ❌ row. A ⚠️ on
adb devicesorappium serverblocks the first run too, and the doctor lists them under "Before your first real run". A ⚠️ fordeviceName,appPackageorappActivitymeans the key is missing fromcapabilities.Start Appium#
Open a second terminal and leave this running:
$ appiumIt listens on port 4723, which matches
urlin the config.Run the tests#
$ optics execute birch-androidThe app opens on the device and the terminal shows each step as it runs.
Write steps for Android#
Tests for Android look like any other Optics test. Elements can be XPaths into the Android UI tree, visible text, or images:
Element_Name,Element_ID
email_field,//android.widget.EditText[@resource-id='com.birch.shop:id/email']
password_field,//android.widget.EditText[@resource-id='com.birch.shop:id/password']
sign_in,Sign in
password,@:trailrunnermodule_name,module_step,param_1,param_2
Open Birch,Launch App
Open Birch,Assert Presence,Sign in,20
Sign in,Enter Text,${email_field},[email protected]
Sign in,Enter Text,${password_field},${password}
Sign in,Press Element,${sign_in}
Sign in,Assert Presence,Trail Runner 2,15Launch App with no value opens appPackage from the config. Pass a package to open a different app: Launch App,com.android.settings. The @: prefix marks password as secret, so it's typed without the prefix and masked in log files. To find XPaths and ids, open the app in optics live or Appium Inspector.
What optics execute checks first#
Before a run starts, optics execute runs a preflight. For Android it checks that:
- The Appium server answers at
url. adbis on your PATH.- adb reports at least one device in the
devicestate.
If a check fails, Optics stops and prints what to do:
Cannot start
No Appium server reachable at http://127.0.0.1:4723.
Start one in another terminal: appium
Then re-run: optics execute birch-androidThe adb checks only run when the plain platformName key is Android, in any capitalization. Optics doesn't read appium:platformName for this check. To skip the preflight, for example when Appium and the devices run on a remote device farm, set OPTICS_SKIP_PREFLIGHT:
$ OPTICS_SKIP_PREFLIGHT=1 optics execute birch-androidoptics dry_run has no preflight, so it works without a device.
Press keys#
Press Keycode sends an Android key by its number:
| Key | Number |
|---|---|
| Back | 4 |
| Home | 3 |
| Enter | 66 |
| Backspace | 67 |
| Tab | 61 |
| Volume up / down | 24 / 25 |
| Recent apps | 187 |
module_name,module_step,param_1
Go back,Press Keycode,4Android's KeyEvent list has every number. To press Enter after typing, you can also write Enter Text Using Keyboard,<enter>. See Press Keycode for details.
Tips#
- App data is kept between runs. Optics starts each session with
noReset: true, so Appium doesn't clear the app's data and a signed-in user stays signed in. AddnoReset: falsetocapabilitiesto start every run from a fresh app. - **Pick a device with
udid.** When several devices are connected, setudidto the serial fromadb devices.deviceNameis only a label. - Include off-screen elements. Android leaves elements that are scrolled out of view out of the UI tree. Add
appium:settings: {allowInvisibleElements: true}undercapabilitiesto include them. - **Switch devices in
optics live.** When you plug in another Android device duringoptics live, Optics notices and switches the session to it. - Android TV uses the same setup. See Test TV apps for remote-control keys.
If it isn't working#
- "No Appium server reachable". Start
appiumin another terminal. If it runs on another port or machine, makeurlmatch. - "No Android device/emulator attached". Run
adb devices. If the phone showsunauthorized, accept the prompt on it. If it showsoffline, reconnect the cable or runadb kill-server, thenadb devicesagain. - **
E0104"Appium capabilities not found in config".**capabilitiesis empty or missing. Add at leastplatformName. - **
E0104"Unsupported platform".** Check the spelling ofplatformName. UseAndroid. - **Appium can't find the UiAutomator2 driver, or complains about
ANDROID_HOME.** Runappium driver install uiautomator2, setANDROID_HOME, and check withappium driver doctor uiautomator2. - The app opens on the wrong screen. Check
appActivity. If the app remembers an old state, setnoReset: false. - A swipe or scroll passes but nothing moves. Appium gesture errors are logged, not raised. Check the screenshots in
execution_output/, and only useupanddownwith Scroll. - An element isn't found. Actions don't wait, so put
Assert Presencebefore them. Troubleshooting covers more cases.