UiAutomator2Options is the type-safe capability builder for Android sessions. Instead of passing raw strings in a HashMap, you get compile-time checking, IDE autocompletion, and meaningful method names that correspond directly to the Appium capability documentation.
The case for typed options over raw maps
Before UiAutomator2Options, sessions were configured with DesiredCapabilities or MutableCapabilities:
// Old approach — no compile-time checking
MutableCapabilities caps = new MutableCapabilities();
caps.setCapability("platformName", "Android");
caps.setCapability("appium:deviceName", "emulator-5554");
caps.setCapability("appium:automationName", "UiAutomator2");
caps.setCapability("appium:app", "/path/to/app.apk");A typo in "appium:automationName" silently produces a capability mismatch error at session creation time. UiAutomator2Options catches those at compile time:
// Typed approach
UiAutomator2Options options = new UiAutomator2Options()
.setDeviceName("emulator-5554")
.setApp("/path/to/app.apk");
// automationName is set automatically — you can't typo itEssential capabilities
UiAutomator2Options options = new UiAutomator2Options()
.setDeviceName("emulator-5554") // AVD name or connected device serial
.setPlatformVersion("13") // Android API level or version string
.setApp(System.getProperty("user.dir")
+ "/src/test/resources/apps/app.apk") // absolute path or URL
.setAppPackage("com.example.myapp") // package name for an installed app
.setAppActivity(".MainActivity") // activity to launch
.setNoReset(true) // don't uninstall/reinstall between sessions
.setAutoGrantPermissions(true); // grant runtime permissions automaticallyUse either setApp() or setAppPackage() + setAppActivity(), not both. If the app is already installed and you just want to launch it, use the package/activity pair and skip setApp().
Connecting to a specific device
When multiple devices are connected (physical + emulator, or multiple emulators for parallel runs), setDeviceName matches against adb devices output:
emulator-5554 device
R38N202ABCD device
Pass the exact serial from adb devices:
options.setUdid("R38N202ABCD"); // physical device by serial
options.setUdid("emulator-5554"); // emulator by AVD namesetUdid is more reliable than setDeviceName when multiple devices are connected.
App reset strategies
Appium's reset behaviour is controlled by three boolean capabilities:
| Capability | Effect |
|---|---|
noReset(false) | Default. Uninstalls and reinstalls the app between sessions. |
noReset(true) | Skips reinstall. App data persists between sessions. |
fullReset(true) | Uninstalls app and clears all data. |
For regression suites, noReset(true) with an explicit driver.terminateApp() / launchApp() sequence gives faster session creation while still starting the app fresh.
Auto-granting permissions
Android 6+ requires runtime permissions. setAutoGrantPermissions(true) grants all requested permissions at install time, avoiding permission dialogs that block test execution.
For apps that should test the permission denial path, omit this capability and handle the dialog explicitly in the test:
options.setAutoGrantPermissions(false);
// In test:
driver.findElement(AppiumBy.id("com.android.permissioncontroller:id/permission_deny_button"))
.click();System port for parallel sessions
When running multiple Android sessions in parallel, each session needs its own systemPort for UiAutomator2's internal server:
// Thread 1
options.setSystemPort(8200);
// Thread 2
options.setSystemPort(8201);Colliding system ports produce address already in use errors. Assign ports from a pool keyed by thread ID, or let Appium choose by setting setSystemPort(0) and accepting whatever port it picks.
Waiting for app launch
By default, Appium waits for the app activity to appear before returning the session. Control the timeout with:
options.setAppWaitActivity("com.example.myapp.SplashActivity,com.example.myapp.MainActivity")
.setAppWaitDuration(Duration.ofSeconds(30));Comma-separated activities tell Appium to accept any of them as the "ready" state. Useful when a splash screen transitions to main before Appium checks.
Full example
public static UiAutomator2Options buildAndroidOptions() {
return new UiAutomator2Options()
.setDeviceName("emulator-5554")
.setPlatformVersion("13")
.setApp(getApkPath())
.setAppPackage("com.example.myapp")
.setAppActivity(".MainActivity")
.setNoReset(true)
.setAutoGrantPermissions(true)
.setNewCommandTimeout(Duration.ofSeconds(60));
}
private static String getApkPath() {
return System.getProperty("user.dir") + "/src/test/resources/apps/app-debug.apk";
}setNewCommandTimeout is the server-side idle timeout. If a test hangs and sends no command for 60 seconds, Appium kills the session and frees the device.