skip to content

In fastlane, which action captures store screenshots on iOS, and which one on Android?

level: juniorimportance: must knowfreq 72%

answer

  1. two platforms, two separate actions
  2. snapshot and screengrab are only aliases
  3. simulators one side, test APK other
  4. canonical names both start with capture_

basics

~20 s

fastlane captures iOS store screenshots with capture_ios_screenshots, better known as snapshot, which drives an XCUITest on simulators; Android uses capture_android_screenshots, known as screengrab, which drives a separate instrumentation test APK on a device or emulator.

solid answer

~40 s

Two different actions, and they are deliberately not symmetric. On iOS, `snapshot` is an alias for the canonical action **`capture_ios_screenshots`**: it builds a UI test target and replays it on every simulator listed in `devices`, and each capture call inside the XCUITest writes a PNG. On Android, `screengrab` is an alias for **`capture_android_screenshots`**: Android UI tests ship as their own APK, so the action takes `app_apk_path` for the app, `tests_apk_path` for the instrumentation suite and `test_instrumentation_runner` for the runner class, then runs them on a device or emulator. For a sailmaker measurement app that means two UI suites, written in two frameworks, whose only shared output is a directory of images per locale.

code

ruby · 28 lines
ruby
platform :ios do
  lane :screenshots do
    capture_ios_screenshots(
      scheme: 'SailmakerMeasureUITests',
      devices: ['iPhone 15 Pro', 'iPad Pro 13-inch (M4)'],
      languages: ['en-US', 'fr-FR', 'ja'],
      output_directory: 'fastlane/screenshots',
      clear_previous_screenshots: true,
      localize_simulator: true,
      override_status_bar: true
    )
  end
end

platform :android do
  lane :screenshots do
    capture_android_screenshots(
      app_apk_path: 'app/build/outputs/apk/debug/app-debug.apk',
      tests_apk_path: 'app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk',
      app_package_name: 'com.sailloft.measure',
      test_instrumentation_runner: 'androidx.test.runner.AndroidJUnitRunner',
      locales: ['en-US', 'fr-FR', 'ja-JP'],
      ending_locale: 'en-US',
      output_directory: 'fastlane/metadata/android',
      clear_previous_screenshots: true
    )
  end
end

go deeper

for a junior

Be ready to name both actions and their aliases in one breath: capture_ios_screenshots (snapshot) and capture_android_screenshots (screengrab). The point of the question is knowing screenshots come from a UI test you wrote, not from the store.

for a middle

Explain the mechanics rather than the names: an XCUITest target replayed on simulators versus an instrumentation test APK installed beside the app, and which option points at each APK on Android.

for a senior

Show you own two capture suites inside one release pipeline: how you stop them drifting apart, and what you do when only one platform's capture lane goes red the day a listing must ship.

for a principal

Own the tradeoff of funding two UI suites whose only product is store artwork. Be ready to argue when hand-curated marketing images beat automated capture and what automation actually buys at locale and device scale.

## Why there are two actions, not one fastlane does not fetch screenshots from anywhere. It **runs your app under a UI test and photographs it**, and how you run an app under test is the single largest difference between the two mobile platforms. So fastlane ships two tools with two option surfaces: - `snapshot` is an alias for the canonical action **`capture_ios_screenshots`**. - `screengrab` is an alias for the canonical action **`capture_android_screenshots`**. Both spellings work in a Fastfile. The short name is the tool's directory in the fastlane monorepo; the canonical `verb_noun` name says what the action does. Around two dozen fastlane tools carry aliases like this — `gym` is `build_app`, `match` is `sync_code_signing`, `deliver` is `upload_to_app_store`, `supply` is `upload_to_play_store`, `frameit` is `frame_screenshots` — and quoting only the nickname reads as second-hand knowledge in an interview. ## What each one actually drives `capture_ios_screenshots` drives **XCUITest on simulators**. You add a UI test target to the sailmaker measurement app's Xcode project, walk the UI to each screen worth showing — the loft's order list, the measurement sheet, the finished cut diagram — and call the helper that writes a PNG. The action builds that target once with the `scheme` you name, then replays it for every simulator in `devices` and every entry in `languages`. `capture_android_screenshots` drives an **instrumentation test on a device or emulator**. Android UI tests are packaged as a *second APK* that is installed next to the app, so the action needs to be told about both: `app_apk_path` for the sailmaker app, `tests_apk_path` for the instrumentation suite, `test_instrumentation_runner` for the runner class that executes it, and `app_package_name` / `tests_package_name` to address them on the device. ## The asymmetry at a glance | | iOS | Android | |---|---|---| | canonical action | `capture_ios_screenshots` | `capture_android_screenshots` | | alias | `snapshot` | `screengrab` | | test technology | XCUITest target in the app project | separate instrumentation test APK | | where it runs | simulators (`devices`, `ios_version`) | device or emulator (`specific_device`, `device_type`) | | locale option | `languages` | `locales`, plus `ending_locale` | | option surface | large, around 53 options | small, around 22 options | That size gap is not cosmetic. The iOS action carries simulator-lifecycle options the Android action has no equivalent for — `erase_simulator`, `concurrent_simulators`, `localize_simulator`, `override_status_bar` — because it owns the machine it runs on and can create and destroy it at will. The Android action is thinner because it delegates to adb and to an instrumentation run on hardware it merely borrows. ## Building the lane for a sailmaker measurement app 1. Write the capture path in each UI suite: launch, seed a known sail order, navigate to each screen, take the shot. 2. Call `capture_ios_screenshots` in the iOS lane with the simulator models and languages the listing needs. 3. Call `capture_android_screenshots` in the Android lane with the app APK, the test APK, the runner and the locales. 4. Optionally pass each output directory through `frame_screenshots` for device bezels. 5. Let each platform's upload action read the resulting per-locale directories. Steps 2 and 3 are the ones candidates wrongly collapse into one. ## What goes wrong when you assume symmetry - 'I will write the UI test once.' You cannot: XCUITest and an Android instrumentation suite are different frameworks, in different languages, against different element trees. - 'screengrab will just run my existing UI tests.' Only once they are built into a test APK and `tests_apk_path` points at it; a lane that never builds that APK dies before the first screenshot. - 'Simulators on both sides.' There is no simulator on the Android path. Capture happens on an emulator or physical hardware, and it mutates that machine's state. - 'One image set covers both stores.' Neither store derives one platform's screenshots from the other; each listing carries its own artwork. ## What interviewers are checking This is a cheap probe for whether you have actually shipped a localized listing. Someone who has answers 'two actions, and here is why they cannot be one', names `capture_ios_screenshots` and `capture_android_screenshots` without being pushed, and mentions the test APK unprompted. Someone who has not usually says 'fastlane takes the screenshots for you', which skips the part that is genuinely work: writing and maintaining two UI suites whose entire product is marketing artwork.

  • Which of the two capture actions needs a second APK built and installed, and why?
    `capture_android_screenshots` does. Android UI tests run as instrumentation and ship as their own APK alongside the app, so you point `app_apk_path` at the sailmaker app, `tests_apk_path` at the test build, and `test_instrumentation_runner` at the runner class. iOS has no equivalent: `capture_ios_screenshots` builds and replays an XCUITest target from the same Xcode project.
  • Why do fastlane examples show both snapshot and capture_ios_screenshots?
    They are the same action. fastlane keeps its famous short tool names as aliases for canonical `verb_noun` action names, so `snapshot` resolves to `capture_ios_screenshots`, `screengrab` to `capture_android_screenshots`, and `frameit` to `frame_screenshots`. Both spellings work in a Fastfile; the canonical name describes the behaviour, the alias names the tool it came from.

saying these in an interview costs you the question

  • Says one fastlane action captures screenshots on both platforms
  • Thinks screengrab drives XCUITest or an iOS simulator
  • Believes screenshots appear without writing a UI test
  • Can only name the nicknames, never a canonical action
  • Assumes the Android side needs no separate test APK