skip to content

Screenshots and Metadata

Automating localized store screenshots with snapshot and screengrab, framing them, and uploading them with the rest of the metadata. Interviewers ask because doing this by hand across devices and locales is exactly the manual work automation exists to remove.

on this pageshow

explore

questions

5

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
open as a page

In fastlane, what does frame_screenshots (frameit) do after iOS or Android screenshots are captured?

level: middleimportance: should knowfreq 41%

basics

~20 s

frame_screenshots, aliased frameit, is pure image post-processing: it reads the PNGs already produced by capture_ios_screenshots on iOS or capture_android_screenshots on Android and writes framed copies, each screenshot composited inside a device bezel with an optional background and title.

open as a page

In fastlane, how do you choose screenshot locales on iOS versus Android?

level: middleimportance: should knowfreq 56%

basics

~20 s

On iOS, capture_ios_screenshots takes a languages list and can localize the simulator itself; on Android, capture_android_screenshots takes a locales list plus ending_locale, the locale the shared device is restored to once the capture run finishes.

open as a page

Your fastlane screenshot lane produces dirty, run-to-run varying store shots — how do you make capture clean and repeatable on iOS and Android?

level: seniorimportance: should knowfreq 47%

basics

~20 s

Control three things separately: the machine, the app data and the artifacts. On iOS use erase_simulator, reinstall_app and override_status_bar; on Android use reinstall_app, stable filenames and ending_locale; and on both use clear_previous_screenshots plus launch_arguments to seed fixed data.

open as a page

In fastlane, how do captured screenshots and localized metadata reach the upload actions on iOS and Android?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Through directories on disk, not return values. Capture writes one folder per locale under output_directory; on Apple, upload_to_app_store reads a separate screenshots_path and metadata_path, while on Google Play upload_to_play_store reads a single metadata_path tree that already contains the images.

open as a page