Appium / Mobile Native

46Appium / Mobile Native Automation

What you will master here

  • What Appium is and how it's the "Selenium for mobile"
  • Native vs hybrid vs mobile-web apps
  • Appium architecture: client → server → driver → device
  • Locators on Android (UiSelector) and iOS (XCUIElement)
  • Gestures (W3C Actions), waits, contexts, app management
  • Real device vs emulator/simulator vs cloud farm
  • Appium 2 plugin model

46.1 Native / Hybrid / Mobile-Web

App typeWhat runsTool
NativePure platform UI (Activity/UIViewController)Appium with UiAutomator2 / XCUITest driver
HybridNative shell + WebView with HTML/JSAppium with switchable context (NATIVE_APP vs WEBVIEW_x)
Mobile-WebMobile Safari/Chrome browserSelenium/Playwright with mobile emulation OR Appium with browser driver

46.2 Architecture

Test code → Appium client lib → Appium Server (Node.js)
                                         │
                       UiAutomator2 driver (Android) / XCUITest driver (iOS)
                                         │
                                  Device / Emulator

Appium speaks the W3C WebDriver protocol — so the same client libs you use for Selenium can drive mobile.

46.3 Setup (Appium 2)

npm i -g appium
appium driver install uiautomator2
appium driver install xcuitest
appium server --port 4723
// Java client
UiAutomator2Options options = new UiAutomator2Options()
    .setDeviceName("Pixel_7_API_34")
    .setApp("/path/to/app.apk")
    .setAutomationName("UiAutomator2");
AndroidDriver driver = new AndroidDriver(
    new URL("http://localhost:4723"), options);

46.4 Locators

// Cross-platform
driver.findElement(AppiumBy.accessibilityId("loginButton"));
driver.findElement(AppiumBy.xpath("//android.widget.Button[@text='Sign in']"));
driver.findElement(AppiumBy.id("com.acme.app:id/email"));

// Android-specific
driver.findElement(AppiumBy.androidUIAutomator(
  "new UiSelector().resourceId(\"com.acme.app:id/email\")"));

// iOS-specific
driver.findElement(AppiumBy.iOSClassChain("**/XCUIElementTypeButton[`name == 'Sign in'`]"));
driver.findElement(AppiumBy.iOSNsPredicate("name == 'Sign in'"));
Best locatorAccessibility ID — works cross-platform and the same string the dev uses for a11y labels. Falls back to platform-specific selectors when needed.

46.5 Gestures (W3C Actions)

// Tap
WebElement btn = driver.findElement(AppiumBy.accessibilityId("buy"));
btn.click();

// Swipe up (scroll down)
PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
Sequence swipe = new Sequence(finger, 0)
  .addAction(finger.createPointerMove(Duration.ZERO,
       PointerInput.Origin.viewport(), 500, 1500))
  .addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
  .addAction(finger.createPointerMove(Duration.ofMillis(500),
       PointerInput.Origin.viewport(), 500, 500))
  .addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
driver.perform(List.of(swipe));

// Long press, pinch, zoom: similar chains

46.6 Hybrid app context switching

// List available contexts
Set<String> contexts = driver.getContextHandles();
// NATIVE_APP, WEBVIEW_com.acme.app

driver.context("WEBVIEW_com.acme.app");   // switch to webview
driver.findElement(By.cssSelector("button.primary")).click();
driver.context("NATIVE_APP");             // back to native

46.7 App lifecycle

driver.installApp("/path/app.apk");
driver.activateApp("com.acme.app");
driver.runAppInBackground(Duration.ofSeconds(5));
driver.terminateApp("com.acme.app");
driver.removeApp("com.acme.app");

// Reset state
driver.executeScript("mobile: clearApp", Map.of("appId", "com.acme.app"));

46.8 Real device vs emulator vs cloud farm

OptionProsCons
Android EmulatorFree, fast snapshotsSlow startup, misses some HW behaviour
iOS SimulatorFree on macOSNo real cellular/Bluetooth
Real device tetheredTrue behaviourOne per host; setup hassle
Cloud farm (BrowserStack/Sauce)Many devices, parallelCost, queueing

46.9 Appium 2 plugin model

Appium 2 split drivers and the server into plugins. Install only what you need: appium driver install uiautomator2 xcuitest mac2 windows. Plus optional plugins (appium plugin install execute-driver) extend Server capabilities.

Module 46 — Appium Q&A

What's Appium?
An open-source server that automates native, hybrid and mobile-web apps using the W3C WebDriver protocol — "Selenium for mobile". Same client libraries; under the hood it delegates to platform drivers (UiAutomator2 for Android, XCUITest for iOS).
Native vs hybrid app — how do you tell?
Native = built with platform SDK (Android Activity, iOS UIViewController). Hybrid = native shell hosting a WebView with HTML/JS. Test the same way functionally but hybrid requires switching context to WEBVIEW_x.
What's the best locator strategy on mobile?
Accessibility ID — devs typically set it for a11y. Cross-platform, stable, semantic. Fall back to platform-specific (Android: resourceId or UiSelector; iOS: class chain or predicate) when accessibility id missing.
How do you switch from native to WebView?
List contexts (driver.getContextHandles()), then driver.context("WEBVIEW_xxx"). Now standard Selenium commands work on the HTML. Switch back with NATIVE_APP.
How do you perform a swipe?
W3C Actions API — build a Sequence with pointerMove, pointerDown, pointerMove (destination), pointerUp. Or use the Appium-specific mobile: swipe / mobile: scrollGesture endpoints for higher-level gestures.
Real device or emulator — which for tests?
95% emulator/simulator (fast, parallel, free). Real device for final smoke before release (hardware bugs, cellular, sensors). For CI scale, cloud farm with both emulators + selective real devices.
What's new in Appium 2?
Drivers and plugins are now separately installable npm packages. Slimmer server. New endpoint structure. Some breaking changes from Appium 1 — desired capabilities replaced with W3C options objects.