App Lifecycle — Launch, Background, Reset

8 min read

Mobile apps have a lifecycle that web pages don't: they are launched, backgrounded, foregrounded, terminated, and reset. Bugs often hide in lifecycle transitions — a draft that disappears when the app is backgrounded, a token that expires after the app is killed, a crash that only happens on cold start after a low-memory event. Testing these scenarios requires specific Appium commands. This lesson covers every lifecycle operation you will need.

App launch

The simplest case: the app is not installed. Set the app capability to the APK or .app path, and Appium installs and launches it automatically when the session starts.

If the app is already installed and you just want to launch it without reinstalling, use appPackage + appActivity (Android) or bundleId (iOS):

Android:

UiAutomator2Options options = new UiAutomator2Options()
    .setDeviceName("emulator-5554")
    .setAppPackage("com.example.myapp")
    .setAppActivity(".MainActivity");

iOS:

XCUITestOptions options = new XCUITestOptions()
    .setDeviceName("iPhone 15 Pro")
    .setBundleId("com.example.myapp");

The app must already be installed for this to work. No app path is needed.

Activating and terminating the app

// Bring the app to the foreground (or launch it if not running)
driver.activateApp("com.example.myapp");     // Android: package name
driver.activateApp("com.example.myapp");     // iOS: bundle ID — same method
 
// Kill the app process
driver.terminateApp("com.example.myapp");
 
// Check if the app is running (returns AppState enum)
ApplicationState state = driver.queryAppState("com.example.myapp");
// Possible states: NOT_INSTALLED, NOT_RUNNING, RUNNING_IN_BACKGROUND_SUSPENDED,
//                  RUNNING_IN_BACKGROUND, RUNNING_IN_FOREGROUND

Backgrounding the app

runAppInBackground sends the app to the background and restores it after the specified duration:

// Background for 5 seconds, then automatically restore
driver.runAppInBackground(Duration.ofSeconds(5));
 
// Background indefinitely (must call activateApp to restore)
driver.runAppInBackground(Duration.ofSeconds(-1));
driver.activateApp("com.example.myapp");

Use this to test:

  • Draft saving: enter text, background, foreground, verify draft is preserved
  • Session timeout: background for longer than the session expiry window
  • Push notification delivery: background the app, trigger a notification, verify badge or banner
  • Background refresh: background, wait for data refresh interval, foreground, verify data updated

Resetting app state

Resetting is distinct from terminating. Terminating kills the process. Resetting clears user data.

Android:

// Clear all app data without uninstalling (fastest)
driver.executeScript("mobile: clearApp", Map.of("appId", "com.example.myapp"));
 
// Or via ADB
Runtime.getRuntime().exec(new String[]{
    "adb", "shell", "pm", "clear", "com.example.myapp"
});

iOS:

// Clear app data on Simulator
driver.executeScript("mobile: clearApp", Map.of("bundleId", "com.example.myapp"));

Using Appium's built-in reset (cross-platform):

The noReset / fullReset capabilities control reset behaviour at session start. For programmatic reset during a test:

driver.resetApp();   // terminates and clears data per the reset capability settings

Installing and uninstalling apps

// Check if installed
boolean isInstalled = driver.isAppInstalled("com.example.myapp");
 
// Install from a local path
driver.installApp("/path/to/app.apk");
 
// Remove the app
driver.removeApp("com.example.myapp");

This is useful in @BeforeSuite to ensure a known-good version is installed, or in @AfterSuite to clean up.

Managing the Android back stack

// Press the Android back button
driver.pressKey(new KeyEvent(AndroidKey.BACK));
 
// Press the Android Home button (sends app to background)
driver.pressKey(new KeyEvent(AndroidKey.HOME));
 
// Open the recent apps drawer
driver.pressKey(new KeyEvent(AndroidKey.APP_SWITCH));

Testing cold start vs warm start

A cold start is when the app process is not running at all. A warm start is when the app is already in memory (backgrounded). Cold start timing is a common performance metric.

// Simulate cold start: terminate then activate
driver.terminateApp("com.example.myapp");
long start = System.currentTimeMillis();
driver.activateApp("com.example.myapp");
// Wait for app to be ready (wait for specific element)
new WebDriverWait(driver, Duration.ofSeconds(10))
    .until(ExpectedConditions.visibilityOfElementLocated(AppiumBy.accessibilityId("home_screen")));
long coldStartDuration = System.currentTimeMillis() - start;

Common lifecycle test scenarios

ScenarioImplementation
Draft preserved after backgroundrunAppInBackground(5s) → verify field value
Login session survives app restartterminateAppactivateApp → verify still logged in
Crash recoveryForce-kill process → relaunch → verify no data loss
First-run onboardingfullReset: true in capabilities → verify onboarding shown
Deep link handlingdriver.executeScript("mobile: deepLink", ...) → verify correct screen

Deep link on Android:

driver.executeScript("mobile: deepLink", Map.of(
    "url", "myapp://product/12345",
    "package", "com.example.myapp"
));

Deep link on iOS:

driver.executeScript("mobile: deepLink", Map.of(
    "url", "myapp://product/12345",
    "bundleId", "com.example.myapp"
));

// tip to track lessons you complete and pick up where you left off across devices.