WebDriverAgent 16.15.0 fixes apps bouncing back after launch; phoneshell's open_app already works around the same symptom by never calling it
A session with no application under test gets no quiescence wait, no crash detection and no alert redirect from WebDriverAgent's own machinery. The fix that shipped this week patches one endpoint. Two independently built iPhone agents barely touch it.
WebDriverAgent 16.15.0, released 12 October 2026, adds an asAppUnderTest flag to POST /wda/apps/launch (PR appium/WebDriverAgent#1289, merged 02:54 UTC that day). Without it, an app launched into a session that has no application under test never becomes one: no default quiescence wait, no crash watch, no redirect to a system alert covering it. The PR's own end-to-end test found every post-launch element lookup failing in 3 of 3 runs without the flag and succeeding in 3 of 3 runs with it. We checked the two iPhone-driving agents we have source access to, this project and the newly public iPhone Use, and neither relies on the endpoint the fix touches.
What changed, and when
The issue report, appium/appium#22889, describes a session created with appium:autoLaunch: false: no app launches at session startup, so the session starts with no application under test. A later mobile: launchApp call (which maps to POST /wda/apps/launch) opens an app, but FBSession's testedApplication property stays nil, because only two things ever set it: passing a bundleId in the session's startup capabilities, or, as of this PR, passing asAppUnderTest: true to /wda/apps/launch. The PR's description names three concrete consequences of staying nil: the launched app does not wait for quiescence unless the request asks for it, is not watched for system alerts even with respectSystemAlerts on, and is not checked for crashes. The author's own words: "in our UI test suite this made taps land during screen transitions."
16.15.0 is the fifth WebDriverAgent release in nine days. 16.14.0 (4 October) added Surface Duo hinge control; 16.14.1 (7 October) stopped sending the idle check to WebKit services, which we covered on 7 October; 16.14.2 (8 October) fixed Duo scroll actions. None of those three touch testedApplication. 16.15.0 does, and it is the one that matters for anything driving a real iPhone through an app-launch call.
| Version | Date | Change | Touches testedApplication |
|---|---|---|---|
| 16.13.6 | 2026-09-30 | Restore stability wait settings when quiescence throws | No |
| 16.14.0 | 2026-10-04 | Duo hinge control and secondary display capture | No |
| 16.14.1 | 2026-10-07 | Skip accessibility idle checks for WebKit services | No |
| 16.14.2 | 2026-10-08 | Align Duo W3C actions and scrolling | No |
| 16.15.0 | 2026-10-12 | Add asAppUnderTest to /wda/apps/launch (PR #1289) | Yes, when the caller opts in |
Source: registry.npmjs.org/appium-webdriveragent version timestamps and github.com/appium/WebDriverAgent releases, read 13 October 2026.
The mechanism: three ways to open an app, one of them protected
WebDriverAgent exposes three different endpoints that bring an app to the foreground, and they are not interchangeable underneath. /wda/apps/launchUnattached runs outside any session, through Apple's LSApplicationWorkspace, and cannot touch testedApplication because no FBSession object is involved at all (confirmed by reading FBCustomCommands.m: the route is declared .withoutSession). /wda/apps/activate calls XCUIApplication activate and returns the app; FBSession's own activateApplicationWithBundleId: is four lines and never assigns testedApplication. Only /wda/apps/launch can set it, and before 16.15.0 only by being the app a bundleId at session creation already pointed to.
What the PR's own test measured
The PR includes an end-to-end run against appium-xcuitest-driver (Appium 3.8.0, UIKitCatalog app, appium:autoLaunch: false, then mobile: launchApp, then two taps that each open a new screen followed immediately by an element lookup on it, three runs each way). Without the flag, WebDriverAgent logged "Quiescence checks are disabled for …" eight times per run, and the lookup right after the second tap failed in every run; the launched app also kept running after the session ended. With asAppUnderTest: true, it logged "set as the application under test" once, then "Waiting up to 10s until … is in idle state" ten times per run, every lookup succeeded, and after the test killed the app with simctl terminate WebDriverAgent correctly reported it "not running, possibly crashed."
Where phoneshell and iPhone Use sit
phoneshell's WDAClient.create_session() is normally called with no bundleId at all: "Passing no bundleId means WDA attaches to whatever is on screen instead of launching something, which is what we want for a phone the human also uses" (phoneshell/wda/client.py). Its open_app() then tries three calls in order, launch_unattached, activate_app, launch_app, polling /wda/activeAppInfo for up to four seconds after each before moving to the next (phoneshell/actions.py:860-872). A comment at that exact spot: "launchUnattached first: it is session-free, so it cannot make WDA switch its app-under-test, which is what used to bounce the phone back to the home screen a couple of seconds after every launch." That is phoneshell's own authors describing a symptom consistent with the gap PR #1289 documents, found and worked around by avoiding the endpoint rather than by a flag that did not exist yet. launch_app() is still reached when the first two calls fail to bring the app forward, and it still does not send asAppUnderTest: that parameter is not in WDAClient.launch_app()'s signature at all.
iPhone Use (github.com/zhongerxin/iPhone-use, created 6 October 2026, MIT licensed, 3,582 stars as of this writing) takes a narrower path to the same place. Its session is created the same way, no bundleId in alwaysMatch (server/wda_client.py:194-196), and its pua_launch_app tool opens apps with exactly one call: self.post("/wda/apps/activate", {"bundleId": bundle_id}, timeout=45) (server/wda_controller.py:594-603). No fallback, no /wda/apps/launch at all. Its foreground check, like phoneshell's, polls the session-free /wda/activeAppInfo (server/wda_controller.py:227-232) rather than asking WebDriverAgent's session for its activeApplication.
| Tool | Session bundleId at creation | App-open call(s) actually used | Ever sets testedApplication | Foreground check relied on | Source |
|---|---|---|---|---|---|
| phoneshell (this repo) | none, attaches to foreground | launchUnattached → activate → launch, in order | only via the 3rd, last-resort call, and no asAppUnderTest sent | own app_state() polling + activeAppInfo | phoneshell/wda/client.py; actions.py:860-872 |
| iPhone Use | none | activate only | never | own active_app() over activeAppInfo | server/wda_client.py:194; wda_controller.py:227,594-603 |
| appium-xcuitest-driver fixture (PR #1289's own test) | none (autoLaunch:false) | launch, via mobile:launchApp | not before 16.15.0; yes if the caller opts in now | WDA's own activeApplication/testedApplication | github.com/appium/WebDriverAgent PR #1289 |
What it means for anyone driving a phone through WDA
- Reading WebDriverAgent's release notes for your own tool means checking which of the three app-open endpoints it calls, not just whether a version number moved. 16.15.0 is a real fix, and it is irrelevant to any tool that never reaches
/wda/apps/launch. - Avoiding an endpoint is not the same as understanding why it broke. phoneshell's comment names the symptom, bouncing back to the home screen, that matches what PR #1289 explains mechanically; neither we nor the comment's author confirmed the two are the identical root cause rather than two WDA behaviors with the same visible effect. We are stating the match, not the proof.
- A tool that polls its own foreground state (
/wda/activeAppInfo, session-free) instead of trusting WebDriverAgent'sactiveApplicationgetter does not needtestedApplicationto be right. Both phoneshell and iPhone Use made that choice independently. - phoneshell's last-resort
launch_app()call is the one path in its own fallback chain that is exposed to the pre-16.15.0 gap today, because it still does not send the new flag. It is reached only when the two cheaper calls both fail to bring the app forward within four seconds each, which our own run logs do not currently count separately from a successfulactivate.
Check it yourself
# WebDriverAgent's own release history and the fix
curl -s https://api.github.com/repos/appium/WebDriverAgent/releases?per_page=10
curl -s https://api.github.com/repos/appium/WebDriverAgent/pulls/1289
git clone --depth 1 --branch v16.15.0 https://github.com/appium/WebDriverAgent.git
grep -n "activateApplicationWithBundleId" -A6 WebDriverAgent/WebDriverAgentLib/Routing/FBSession.m
grep -n "withoutSession" -B2 WebDriverAgent/WebDriverAgentLib/Commands/FBCustomCommands.m | grep -i launchunattached
# phoneshell: the escalating fallback and its one unprotected last resort
grep -n "launch_unattached, self.wda.activate_app, self.wda.launch_app" phoneshell/actions.py
sed -n '376,392p' phoneshell/wda/client.py # launch_app() has no asAppUnderTest parameter
# iPhone Use: the session it creates and the one call its launch tool makes
curl -s https://raw.githubusercontent.com/zhongerxin/iPhone-use/main/server/wda_client.py | sed -n '188,200p'
curl -s https://raw.githubusercontent.com/zhongerxin/iPhone-use/main/server/wda_controller.py | grep -n "apps/activate\|apps/launch"
What would prove this wrong
We claim phoneshell's three-call fallback keeps its risky path, launch_app() without asAppUnderTest, as a rare last resort rather than the common case. That is wrong if launchUnattached or activate fail to bring an app forward often enough that launch_app() fires on a meaningful fraction of real runs; nothing in this repo currently logs which of the three calls succeeded. By 31 December 2026 we expect open_app() to log which attempt won, and, separately, for WDAClient.launch_app() to still not expose asAppUnderTest, since no open issue in this repo references it today. Both are checkable by grepping runtime/logs and phoneshell/wda/client.py on that date.
Sources
- Appium project, "feat: add asAppUnderTest flag to /wda/apps/launch", PR #1289, merged 12 October 2026; issue appium/appium#22889; driver-side appium-xcuitest-driver#3004.
- Appium project, WebDriverAgent releases and npm version history, read 13 October 2026.
- zhongerxin, iPhone Use, created 6 October 2026, MIT license,
server/wda_client.pyandserver/wda_controller.py, read 13 October 2026. - Blolabel, phoneshell:
phoneshell/wda/client.py,phoneshell/actions.py, read 13 October 2026. - Blolabel, "WebDriverAgent 16.14.1 stops sending its idle check to WebKit", 7 October 2026.