Your Appium cattle-auction suite records video on iOS but returns nothing on Android — why?
answer
- a green platform proves nothing about the other
- screenshot first, to isolate the layer
- the payload comes from stop, not start
- Android capture runs in a second process
- io.appium.settings holds the projection
basics
~20 sThe recorders are different products. Apple's video comes from XCTest inside WebDriverAgent; Android's is produced by the io.appium.settings helper application, so a missing helper, an ungranted media projection, or a skipped stop call returns nothing.
solid answer
~40 sNothing about a working Apple recording predicts a working Android one, because the two share no mechanism. XCUITest's `mobile: startXCTestScreenRecording` runs inside WebDriverAgent; Android's `mobile: startMediaProjectionRecording` is declared by `appium-android-driver` and captured by the **`io.appium.settings` helper application**, since screen capture on Android is privileged. So work down the Android-specific layers: confirm `GET /session/:sessionId/screenshot` still succeeds (which isolates capture from session health), confirm the helper app is present and able to project, confirm `mobile: stopMediaProjectionRecording` actually ran while the session was alive — the payload comes back from the *stop* call — and confirm you did not start through the legacy `start_recording_screen` route and stop through the execute method.
go deeper
Recall that Android and Apple use different recording commands and that the video comes back from the stop call, so a start with no stop leaves you with nothing to attach.
Explain the mechanism gap: Android capture is privileged and delegated to the io.appium.settings helper application, while Apple capture is XCTest's own facility inside WebDriverAgent.
Demonstrate the isolation sequence — screenshot first, then start versus stop, then session lifetime, then the helper app — and show how you make an empty payload fail loudly instead of writing a zero-byte file.
Own device provisioning as part of evidence reliability: the Android recorder has a per-device dependency, so a fleet policy that assumes uniform capture capability will quietly lose artefacts on some models.
## Why one platform can succeed while the other returns nothing The symptom looks like a bug in "recording", but recording is not one feature in Appium. On Apple platforms the XCUITest driver declares `mobile: startXCTestScreenRecording` and `mobile: stopXCTestScreenRecording`, backed by XCTest inside WebDriverAgent. On Android the pair is `mobile: startMediaProjectionRecording` and `mobile: stopMediaProjectionRecording`, declared in `appium-android-driver` and inherited by the UiAutomator2 and Espresso drivers — but the frames themselves are captured by the **`io.appium.settings` helper application** installed on the device, because Android screen capture is a privileged operation the automation server cannot perform on its own. That second process is the whole difference. A green Apple recording tells you the harness calls its start and stop methods correctly. It tells you nothing about a helper app on an Android device. ## Isolate the layer before you change anything Run these in order; each one eliminates a layer: 1. Call `GET /session/:sessionId/screenshot` on the same Android session. If the still comes back, the session and the driver are healthy and the fault is in the recording path specifically. 2. Check what the start call returned versus what the **stop** call returned. The video payload comes back from the stop call, so a harness that only ever calls start has no artefact by construction. 3. Confirm the stop call ran **before** `DELETE /session/:sessionId`. A teardown that deletes the session in a fixture that runs earlier than the artefact hook loses the payload with no error worth reading. 4. Confirm the driver in play actually extends `appium-android-driver`. A driver that does not declare the media-projection methods fails as an unknown command, which is a different signature from an empty payload. 5. Confirm the stop call was not made without a matching start on that session — stopping something that was never started yields an empty result rather than a loud failure. ## The Android-specific causes Once the layer is isolated, the candidates are concrete: - **The helper application is missing or stale.** `io.appium.settings` is what captures the frames. If it has been removed from the device, or the device carries an old build, media-projection recording has nowhere to run even though every other command still works. - **The media projection was not granted.** Screen capture on Android requires the platform to authorise it. If that grant is not in place for the helper, the recorder produces nothing while the rest of the session behaves normally. - **Start and stop came from different surfaces.** Appium 3 moved the old `start_recording_screen` route into the drivers, which re-add it un-deprecated, so both that route and `mobile: startMediaProjectionRecording` exist on an Android session. Starting through one and stopping through the other does not pair up. - **The session died mid-run.** Any teardown that ends the session between start and stop takes the artefact with it, and the failure reads as "no video" rather than "session gone". - **The device is one where projection is unavailable.** Not every image in a fleet supports the same capture facility, so a fleet-wide green result on one device model proves nothing about another. ## The Apple-side checks that do not transfer The temptation is to reuse the Apple diagnostic loop. It does not apply: | Question | Apple (XCUITest) | Android (the Android drivers) | |---|---|---| | Is a recording currently active? | ask `mobile: getXCTestScreenRecordingInfo` | not available here — the harness must track it | | Who captures the frames? | XCTest inside WebDriverAgent | the `io.appium.settings` helper application | | Is there a second recorder? | yes, `mobile: startScreenRecording` over the MJPEG stream | the live path is `mobile: startScreenStreaming` | Because XCUITest exposes a status query and the Android side, in this command surface, does not, an Android harness has to keep its own record of whether a recording is running. Teams that assume symmetry here write a stop call that fires unconditionally, gets an empty payload, and writes a zero-byte file that nobody notices until a triage session needs it. ## Making the failure loud instead of silent The reason this defect survives for weeks is that every step involved returns successfully. The fix is to stop trusting silence: - Assert on the **size** of what the stop call returned, not merely that the call did not throw. - Log which recorder was used and on which platform, so a zero-byte artefact identifies its own path. - Fail the artefact hook, not the test, when the payload is empty — you want the signal without turning a passing bid-submission case red. - Verify the Android helper application's presence as part of device provisioning rather than discovering it from a missing video. - Keep the start/stop pair in one helper so a refactor cannot separate them across fixtures. What evidence a suite ought to keep, and where it is attached afterwards, is a separate architectural decision. The Appium-level lesson is narrower and sharper: the Android and Apple recorders are different products with different dependencies, and only one of them depends on a second application being present on the device.
- The stop call succeeds but returns an empty payload. How do you turn that into a usable signal?Assert on payload size in the artefact hook and log the platform and the recorder used. An empty return is Appium reporting that nothing was recorded, not an error, so only your own check surfaces it. Fail the hook rather than the test, so a passing bid-submission case is not reddened by an evidence problem.
- Why is asking whether a recording is running easy on Apple and awkward on Android?XCUITest declares `mobile: getXCTestScreenRecordingInfo`, so an Apple session can query the driver directly. The Android media-projection surface exposes no equivalent status method, so the harness has to track start and stop itself. Assuming symmetry produces unconditional stop calls and zero-byte artefacts.
saying these in an interview costs you the question
- Assumes one recording mechanism serves both platforms
- Blames the Appium server when only Android video is missing
- Never checks whether the stop call actually ran
- Forgets that Android capture depends on the io.appium.settings helper app
- Treats a non-throwing stop call as proof a video exists
- Mixes the legacy recording route with the mobile: execute method