| name | automating-screenshots |
| description | Fastlane snapshot and screengrab for automated App Store and Play Store screenshots. Use when setting up screenshot automation, configuring device sizes, or generating localised screenshots. |
Fastlane Screenshot Automation Reference
Plugin Tools
Before setting up screenshot automation, check your environment:
cd /path/to/expo-toolkit && npm run list-devices
node tools/list-devices.js --ios
node tools/list-devices.js --android
node tools/list-devices.js --json
This shows:
- Available iOS simulators with App Store screenshot sizes highlighted
- Available Android emulators
- Fastlane installation status
Tools Overview
Fastlane is a suite of tools for automating mobile app development workflows:
| Tool | Platform | Purpose |
|---|
snapshot | iOS | Automated screenshots |
screengrab | Android | Automated screenshots |
frameit | Both | Add device frames to screenshots |
deliver | iOS | Upload to App Store Connect |
supply | Android | Upload to Play Console |
match | iOS | Code signing management |
pilot | iOS | TestFlight management |
Installation
Via Homebrew (Recommended)
brew install fastlane
Via RubyGems
sudo gem install fastlane -NV
Verify Installation
fastlane --version
Project Setup
Initialise Fastlane
fastlane init
This creates:
fastlane/Fastfile - Lane definitions
fastlane/Appfile - App configuration
Directory Structure
your-project/
├── ios/
│ └── fastlane/
│ ├── Fastfile
│ ├── Appfile
│ ├── Snapfile
│ └── screenshots/
├── android/
│ └── fastlane/
│ ├── Fastfile
│ ├── Appfile
│ ├── Screengrabfile
│ └── screenshots/
└── ...
iOS Screenshot Automation (Snapshot)
Initialise Snapshot
cd ios
fastlane snapshot init
Creates:
fastlane/Snapfile - Snapshot configuration
fastlane/SnapshotHelper.swift - UI test helper
Snapfile Configuration
devices([
"iPhone 15 Pro Max",
"iPhone 14 Plus",
"iPhone 8 Plus",
"iPad Pro (12.9-inch) (6th generation)"
])
languages([
"en-GB",
"en-US",
"de-DE",
"fr-FR",
"ja",
"zh-Hans"
])
output_directory("./fastlane/screenshots")
clear_previous_screenshots(true)
scheme("YourAppUITests")
workspace("../YourApp.xcworkspace")
override_status_bar(true)
launch_arguments(["-screenshots"])
concurrent_simulators(true)
stop_after_first_error(false)
skip_open_summary(false)
SnapshotHelper Setup
- Add
SnapshotHelper.swift to your UI Test target
- Import in your test file
- Call
setupSnapshot(app) in setUp
UI Test for Screenshots
Create YourAppUITests/ScreenshotTests.swift:
import XCTest
class ScreenshotTests: XCTestCase {
var app: XCUIApplication!
override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication()
setupSnapshot(app)
app.launch()
}
override func tearDownWithError() throws {
app = nil
}
func testTakeScreenshots() throws {
sleep(2)
snapshot("01_HomeScreen")
app.buttons["FeatureButton"].tap()
sleep(1)
snapshot("02_FeatureScreen")
app.tabBars.buttons["Settings"].tap()
sleep(1)
snapshot("03_SettingsScreen")
app.cells["ProfileCell"].tap()
sleep(1)
snapshot("04_ProfileScreen")
snapshot("05_DarkModeScreen")
}
}
Running Snapshot
cd ios
fastlane snapshot
fastlane snapshot --devices "iPhone 15 Pro Max"
fastlane snapshot --languages "en-GB"
fastlane snapshot --skip_build
Android Screenshot Automation (Screengrab)
Initialise Screengrab
cd android
fastlane screengrab init
Creates:
fastlane/Screengrabfile - Configuration
Screengrabfile Configuration
app_package_name("com.yourcompany.yourapp")
use_tests_in_classes(["com.yourcompany.yourapp.ScreenshotTests"])
app_apk_path("app/build/outputs/apk/debug/app-debug.apk")
tests_apk_path("app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk")
locales([
"en-US",
"en-GB",
"de-DE",
"fr-FR",
"ja-JP",
"zh-CN"
])
output_directory("./fastlane/screenshots")
clear_previous_screenshots(true)
exit_on_test_failure(false)
ending_locale("en-US")
skip_open_summary(false)
Add Screengrab Dependency
In app/build.gradle:
dependencies {
// ...
androidTestImplementation 'tools.fastlane:screengrab:2.1.1'
}
Instrumented Test for Screenshots
Create app/src/androidTest/java/com/yourcompany/yourapp/ScreenshotTests.kt:
package com.yourcompany.yourapp
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Before
import org.junit.ClassRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import tools.fastlane.screengrab.Screengrab
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
import tools.fastlane.screengrab.locale.LocaleTestRule
@RunWith(AndroidJUnit4::class)
class ScreenshotTests {
companion object {
@get:ClassRule
@JvmStatic
val localeTestRule = LocaleTestRule()
}
@Before
fun setUp() {
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
}
@Test
fun takeScreenshots() {
ActivityScenario.launch(MainActivity::class.java)
Thread.sleep(2000)
Screengrab.screenshot("01_HomeScreen")
onView(withId(R.id.feature_button)).perform(click())
Thread.sleep(1000)
Screengrab.screenshot()
onView(withId(R.id.settings_tab)).perform(click())
Thread.sleep()
Screengrab.screenshot()
onView(withText()).perform(click())
Thread.sleep()
Screengrab.screenshot()
}
}
Running Screengrab
cd android
./gradlew assembleDebug assembleAndroidTest
fastlane screengrab
fastlane screengrab --locales "en-GB"
Framing Screenshots (Frameit)
Add device frames and marketing text to screenshots.
Basic Usage
fastlane frameit
Configuration (frameit.json)
Create fastlane/screenshots/frameit.json:
{
"default": {
"title": {
"font": "./fonts/Helvetica-Bold.ttf",
"font_size": 128,
"color": "#000000"
},
"background": "#FFFFFF",
"padding": 50,
"show_complete_frame": true,
"stack_title": false
},
"data": [
{
"filter": "01_HomeScreen",
"title": {
"text": "Manage your tasks effortlessly"
}
},
{
Frameit Options
| Option | Description |
|---|
silver | Use silver device frame |
rose_gold | Use rose gold frame |
force_device_type | Force specific device |
use_platform | Use platform-specific frames |
fastlane frameit silver
fastlane frameit --force_device_type "iPhone 14 Pro"
Fastfile Lanes
Define reusable workflows in Fastfile:
iOS Fastfile
default_platform(:ios)
platform :ios do
desc "Capture screenshots"
lane :screenshots do
snapshot
frameit(white: true)
end
desc "Upload screenshots to App Store Connect"
lane :upload_screenshots do
deliver(
skip_binary_upload: true,
skip_metadata: true,
screenshots_path: "./fastlane/screenshots"
)
end
desc "Full screenshot workflow"
lane :refresh_screenshots do
screenshots
upload_screenshots
end
end
Android Fastfile
default_platform(:android)
platform :android do
desc "Build debug APKs"
lane :build_for_screenshots do
gradle(
task: "assemble",
build_type: "Debug"
)
gradle(
task: "assemble",
build_type: "AndroidTest"
)
end
desc "Capture screenshots"
lane :screenshots do
build_for_screenshots
screengrab
end
desc "Upload screenshots to Play Console"
lane :upload_screenshots do
supply(
skip_upload_apk: true,
skip_upload_aab: true,
skip_upload_metadata: true,
skip_upload_changelogs: true,
images_path: "./fastlane/screenshots"
)
end
end
Running Lanes
cd ios
fastlane screenshots
fastlane upload_screenshots
cd android
fastlane screenshots
fastlane upload_screenshots
Required Screenshot Sizes
iOS (App Store Connect)
| Display Size | Resolution | Device |
|---|
| 6.7" | 1290 x 2796 | iPhone 15 Pro Max |
| 6.5" | 1284 x 2778 | iPhone 14 Plus |
| 5.5" | 1242 x 2208 | iPhone 8 Plus |
| 12.9" iPad | 2048 x 2732 | iPad Pro |
Note: App Store Connect can auto-scale from 6.7" to smaller sizes.
Android (Play Console)
| Type | Minimum | Recommended |
|---|
| Phone | 320px min side | 1080 x 1920 |
| 7" Tablet | 1024 x 500 | 1200 x 1920 |
| 10" Tablet | 1024 x 500 | 1600 x 2560 |
Localisation
Setting Up Localised Screenshots
- Configure languages in Snapfile/Screengrabfile
- Use localised strings in your app
- Capture screenshots for each locale
iOS Localisation in Tests
func testTakeLocalizedScreenshots() throws {
snapshot("01_HomeScreen")
}
Android Localisation in Tests
@Test
fun takeLocalizedScreenshots() {
Screengrab.screenshot("01_HomeScreen")
}
Troubleshooting
Common iOS Issues
Simulator not found:
xcrun simctl list devices
devices(["iPhone 15 Pro Max"])
UI test target issues:
- Ensure SnapshotHelper.swift is in UI Test target
- Check scheme includes UI Test target
- Verify setupSnapshot(app) is called
Status bar not overridden:
override_status_bar(true)
Common Android Issues
APK not found:
./gradlew assembleDebug assembleAndroidTest
Emulator connection issues:
adb devices
emulator -avd Pixel_6_API_34
Permission issues:
@get:Rule
val grantPermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
General Issues
Screenshots too slow:
- Use
concurrent_simulators(true) (iOS)
- Run fewer devices at once
- Use
skip_build if already built
Memory issues:
number_of_retries(3)
concurrent_simulators(false)
Best Practices
Screenshot Quality
- Use realistic data - Not Lorem ipsum
- Clean status bar - Use override_status_bar
- Consistent state - Reset app between captures
- Wait for animations - Add appropriate sleeps/waits
- Test edge cases - Empty states, full lists, etc.
Organisation
- Name screenshots descriptively -
01_Home, 02_Feature
- Use consistent numbering - Ensures correct order
- Group by feature - Logical organisation
- Document test scenarios - What each screenshot shows
Performance
- Build once, capture many - Use
skip_build
- Parallel capture -
concurrent_simulators(true)
- Target specific devices - When debugging
- CI integration - Automate in pipeline
Integration with EAS/Expo
For Expo projects:
- Run
npx expo prebuild to generate native projects
- Configure Fastlane in
ios/ and android/ directories
- Run screenshot automation as normal
- Native projects are regenerated on prebuild, so:
- Keep Fastfile in project root, copy on prebuild
- Or add to
.gitignore and regenerate as needed
{
"screenshots:ios": "cd ios && fastlane snapshot",
"screenshots:android": "cd android && fastlane screengrab"
}
Quick Reference
cd ios
fastlane snapshot init
fastlane snapshot
fastlane frameit
fastlane deliver screenshots
cd android
fastlane screengrab init
./gradlew assembleDebug assembleAndroidTest
fastlane screengrab
fastlane supply images
fastlane snapshot --devices "iPhone 15 Pro Max"
fastlane snapshot --languages "en-GB,de-DE"
fastlane snapshot --skip_build
fastlane screengrab --locales "en-US"