Hi,
we are facing a recurring issue with WebView context handling in our hybrid Android app.
-
We can see the WebView in getContexts() output, but sometimes switching context to it (driver.switchContext(WEBVIEW_…)) either hangs or getContexts() itself fails with a timeout.
-
When this happens, the test just freezes because the WebView context never gets attached, even though the app is still running and responsive.
-
It occurs randomly — sometimes the context is found and works, other times it just times out.
Here are the actual capabilities we use:
capabilities: [{
platformName: "Android",
"appium:deviceName": "emulator-5554",
"appium:app": apkPath,
"appium:appPackage": customerConfig.aliasApk,
"appium:ignoreUnimportantViews": true,
"appium:appWaitActivity": "*",
"appium:automationName": "UiAutomator2",
"appium:autoGrantPermissions": true,
"appium:noReset": true,
"appium:fullReset": false,
"appium:adbExecTimeout": 120000,
"appium:ensureWebviewsHavePages": true,
"appium:recreateChromeDriverSessions": true,
"appium:webviewConnectTimeout": 30000,
"appium:newCommandTimeout": 180,
"appium:chromedriverAutodownload": true,
"appium:nativeWebScreenshot": true
}]
We run the tests on:
Here is the relevant part of our code for WebView handling:
private async getWebviewsWithBackoff(): Promise<string[]> {
const once = async () => {
// @ts-ignore
const list = await driver
.getContexts({ returnDetailedContexts: true })
.catch(() => driver.getContexts());
return (list as any[])
.map((c) => (typeof c === 'string' ? c : c.id))
.filter(
(id) =>
id &&
id.toUpperCase().startsWith('WEBVIEW') &&
id.toLowerCase().includes('company.product')
) as string[];
};
let wv = await once();
if (wv.length) return wv;
await driver.pause(500);
return await once();
}
private async tryWebview(totalTimeout: number): Promise<boolean> {
return HybridGate.run(async () => {
const end = Date.now() + totalTimeout;
const original = await this.getContextSafe();
try {
let attempt = 0;
while (Date.now() < end && attempt < this.opts.webviewRetries) {
attempt++;
let webviews: string[] = [];
try {
webviews = await this.withTimeout(
this.getWebviewsWithBackoff(),
this.opts.opTimeoutMs,
'getContexts/backoff'
);
} catch (e) {
this.warn(`getContexts failed: ${e}`);
await driver.pause(this.opts.retryIntervalMs);
continue;
}
this.log(`contexts: ${JSON.stringify(webviews)}`);
if (!webviews.length) {
await driver.pause(this.opts.retryIntervalMs);
continue;
}
for (const id of webviews) {
try {
await this.withTimeout(
driver.switchContext(id),
this.opts.opTimeoutMs,
`switchContext(${id})`
);
// Check if DOM is ready
const hasDom = await this.safeExecute<boolean>(() => {
try {
return !!document.body && document.body.innerText.trim().length > 0;
} catch {
return false;
}
}, 'hasDom');
this.log(`WEBVIEW ${id} → hasDom=${hasDom}`);
if (hasDom) return true;
} catch (e) {
this.warn(`switchContext(${id}) failed: ${e}`);
}
}
await driver.pause(this.opts.retryIntervalMs);
}
return false;
} catch (e) {
this.warn(`WEBVIEW exception: ${e}`);
return false;
} finally {
try {
if (original) await driver.switchContext(original);
else await driver.switchContext('NATIVE_APP');
} catch {}
await driver.pause(120);
}
});
}
WDIO console logs (examples)
[TitleTextElement] ℹ NATIVE not found – going to WEBVIEW…
[TitleTextElement] contexts: ["WEBVIEW_company.procuct.mobileclient.androidclient.customerApp"]
[TitleTextElement] handles(WEBVIEW_company.procuct.mobileclient.androidclient.customerApp):
["76AF18C84...","B56A1E96...","16DDDCEB...","46C0B639...","274F2610...","6B31FBA1...","EFDD5248...","D30082FA..."]
[TitleTextElement] window 76AF18C84... → hasDom=true
Sometimes we get a direct timeout during context discovery:
[TitleTextElement] getContexts failed: Error: [timeout] getContexts/backoff (8000ms)
Appium server logs (examples)
[AndroidUiautomator2Driver] Getting a list of available webviews
[ADB] Running '... adb.exe -s emulator-5554 shell cat /proc/net/unix'
[AndroidUiautomator2Driver] Parsed 3 active devtools sockets: ["@stetho_...","@webview_devtools_remote_30194","@webview_devtools_remote_20494"]
[AndroidUiautomator2Driver] Collecting CDP data of 3 webviews
[AndroidUiautomator2Driver] Forwarding remote port ... to local ...
[AndroidUiautomator2Driver] CDP data for 'WEBVIEW_stetho_...' cannot be collected. Original error: timeout of 2000ms exceeded
[AndroidUiautomator2Driver] Removing forwarded port socket connection: 12000
...
[AndroidUiautomator2Driver] CDP data collection completed
[AndroidUiautomator2Driver] WEBVIEW_30194 mapped to pid 30194
[AndroidUiautomator2Driver] Getting process name for webview 'WEBVIEW_30194'
[ADB] Running '... adb.exe -s emulator-5554 shell ps -A'
And on the client side, we see timeouts waiting for contexts right after:
[TitleTextElement] ℹ NATIVE not found – going to WEBVIEW…
[TitleTextElement] getContexts failed: Error: [timeout] getContexts/backoff (8000ms)
In other runs we see:
WebDriverError: no such window: target window already closed
from unknown error: web view not found (Session info: chrome=133.0.6943.137)
I tried to describe it properly. Please advise. I can already switch between the native app and web view, but the test is unstable in the web view and gets stuck when searching for context. It seems to me that after a while, the server can’t keep up, and it just runs slower and slower until it freezes completely, and the test stops, and what used to take a second now takes minutes. It’s as if it’s overloaded.
Thank you for your advice. It’s very important for me to fix this. We can’t test our product right now.
If anyone would like to help me further, I can provide my contact details for better communication.
Thank you very much for your advice.