How can I switch between a native Android app and Chrome browser using Serenity BDD with Appium, and switch back reliably?

I’m using Serenity BDD with Appium v2.3.12 to automate a scenario that starts in a native Android app, opens Chrome to validate a form, and then returns to the native app for login.

I’m currently using serenity.properties to configure Appium with UIAutomator2.

To switch to Chrome, I manually create a new AppiumDriver with browserName = Chrome. This works fine, but the issue arises when switching back to the native context:

Using launchApp() or resetApp() causes driver failure, elements are no longer found, and getPageSource() throws a WebDriverException.

Quitting the original driver and trying to reuse it causes NoSuchSessionException.

Creating a third AppiumDriver works but breaks Serenity’s PageObject mapping.

This switch works well on iOS, so I suspect UIAutomator2 and Serenity’s driver management might be the issue.

I’m looking for a clean way to switch contexts or drivers in Serenity so I can test both native and browser flows on Android without losing stability or PageObject mapping.

Has anyone tackled this with Serenity BDD + Appium on Android?

I ran into this same pain point using Serenity + Appium for a hybrid workflow. What worked for us was using Android intents instead of creating a new Appium driver.

We launched Chrome using adb shell am start with the correct URL, then used Appium’s context switching to move between NATIVE_APP and WEBVIEW_chrome.

That way, we didn’t create a second driver at all, Serenity kept its context, and we preserved PageObject stability. You’ll need to poll for context availability though, since Chrome loads asynchronously.

We had a similar case and our workaround was to avoid Serenity managing multiple drivers directly. Instead, we configured Serenity to manage only the native app context.

Then, for the Chrome part, we injected a raw Appium driver manually outside Serenity’s lifecycle, just for the browser interaction.

Once done, we closed that temporary driver and called activateApp() with the app package ID to bring the native context back. No need to reset the app or relaunch, it kept the session and PageObject bindings intact.