Claude-skill-registry android-screenshot-automation
Setup automated screenshot capture for Play Store using Fastlane Screengrab
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/android-screenshot-automation" ~/.claude/skills/majiayu000-claude-skill-registry-android-screenshot-automation && rm -rf "$T"
skills/data/android-screenshot-automation/SKILL.mdAndroid Screenshot Automation
Setup automated screenshot capture using Fastlane Screengrab, integrating with existing e2e test infrastructure.
Prerequisites
completed/devtools:android-fastlane-setup
completed (UI Automator tests exist)/devtools:android-e2e-tests- Emulator or device available for testing
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
| screens | Yes | - | List of screens to capture (e.g., home, settings, profile) |
| locales | No | en-US | Comma-separated locales (e.g., en-US,de-DE,es-ES) |
Process
Step 1: Add Screengrab Dependency
Add to
app/build.gradle.kts:
dependencies { // Existing test dependencies... // Screengrab for automated screenshots androidTestImplementation("tools.fastlane:screengrab:2.1.1") }
Sync Gradle after adding.
Step 2: Create Debug Manifest
Create or update
app/src/debug/AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- Screengrab permissions --> <!-- Store screenshots on external storage (API <= 18) --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" /> <!-- Change device locale during tests --> <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" tools:ignore="ProtectedPermissions" /> <!-- Enable demo mode for clean status bar --> <uses-permission android:name="android.permission.DUMP" tools:ignore="ProtectedPermissions" /> </manifest>
Step 3: Create Demo Mode Helper (Optional but Recommended)
Create
app/src/androidTest/{package_path}/screenshots/DemoModeRule.kt:
package {PACKAGE_NAME}.screenshots import android.os.ParcelFileDescriptor import androidx.test.platform.app.InstrumentationRegistry import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement import java.io.BufferedReader import java.io.InputStreamReader /** * JUnit Rule that enables Android Demo Mode for clean status bar screenshots. * * Demo mode shows: * - Full battery (100%) * - Full signal strength * - Fixed time (12:00) * - No notifications */ class DemoModeRule : TestRule { override fun apply(base: Statement, description: Description): Statement { return object : Statement() { override fun evaluate() { enableDemoMode() try { base.evaluate() } finally { disableDemoMode() } } } } private fun enableDemoMode() { executeShellCommand("settings put global sysui_demo_allowed 1") executeShellCommand("am broadcast -a com.android.systemui.demo -e command enter") executeShellCommand("am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1200") executeShellCommand("am broadcast -a com.android.systemui.demo -e command battery -e level 100 -e plugged false") executeShellCommand("am broadcast -a com.android.systemui.demo -e command network -e wifi show -e level 4") executeShellCommand("am broadcast -a com.android.systemui.demo -e command network -e mobile show -e datatype none -e level 4") executeShellCommand("am broadcast -a com.android.systemui.demo -e command notifications -e visible false") } private fun disableDemoMode() { executeShellCommand("am broadcast -a com.android.systemui.demo -e command exit") } private fun executeShellCommand(command: String) { val instrumentation = InstrumentationRegistry.getInstrumentation() val automation = instrumentation.uiAutomation val pfd: ParcelFileDescriptor = automation.executeShellCommand(command) val reader = BufferedReader(InputStreamReader(ParcelFileDescriptor.AutoCloseInputStream(pfd))) reader.readLines() // Consume output reader.close() } }
Step 4: Create Screenshot Test Class
Create
app/src/androidTest/{package_path}/screenshots/ScreenshotTest.kt:
package {PACKAGE_NAME}.screenshots import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.matcher.ViewMatchers.withId import org.junit.Before import org.junit.ClassRule import org.junit.Rule import org.junit.Test import org.junit.rules.RuleChain import org.junit.runner.RunWith import tools.fastlane.screengrab.Screengrab import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy import tools.fastlane.screengrab.locale.LocaleTestRule import {PACKAGE_NAME}.R import {PACKAGE_NAME}.MainActivity /** * Automated screenshot capture for Play Store listing. * * Run with: bundle exec fastlane screenshots * * Screenshots are saved to: fastlane/metadata/android/{locale}/images/phoneScreenshots/ */ @RunWith(AndroidJUnit4::class) class ScreenshotTest { companion object { // Automatically switches device locale between test runs @get:ClassRule @JvmField val localeTestRule = LocaleTestRule() } // Launch main activity for each test @get:Rule val activityRule = ActivityScenarioRule(MainActivity::class.java) // Enable demo mode for clean status bar (optional) @get:Rule val demoModeRule = DemoModeRule() @Before fun setup() { // Use UI Automator strategy for better screenshots // This captures dialogs, shadows, and system UI correctly Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy()) } @Test fun captureScreenshots() { // Wait for app to fully load Thread.sleep(1000) // Screenshot 1: Main/Home screen Screengrab.screenshot("01_home") // TODO: Navigate to next screen and capture // Example: // onView(withId(R.id.settings_button)).perform(click()) // Thread.sleep(500) // Screengrab.screenshot("02_settings") // TODO: Add more screenshots as needed // Recommendation: Capture 4-8 key screens that showcase your app's features } // Optional: Separate test methods for different flows // This helps organize screenshots and makes debugging easier @Test fun captureOnboardingFlow() { // If your app has onboarding, capture those screens // Screengrab.screenshot("onboarding_01_welcome") // onView(withId(R.id.next_button)).perform(click()) // Screengrab.screenshot("onboarding_02_features") } }
Important: Replace
{PACKAGE_NAME} with your actual package name and customize the screenshot capture logic.
Step 5: Update Screengrabfile
Ensure
./fastlane/Screengrabfile has the correct test class:
# Use the screenshot test class use_tests_in_classes(["{PACKAGE_NAME}.screenshots.ScreenshotTest"])
Step 6: Run Screenshots
# Build and capture screenshots bundle exec fastlane screenshots # Or run screengrab directly bundle exec fastlane run capture_android_screenshots
Adding Multiple Device Sizes
For tablet screenshots, you can run screengrab with different device types:
# Add to Fastfile desc "Capture screenshots for all device types" lane :screenshots_all_devices do # Phone screenshots capture_android_screenshots(device_type: "phone") # 7-inch tablet (requires tablet emulator running) # capture_android_screenshots(device_type: "sevenInch") # 10-inch tablet (requires tablet emulator running) # capture_android_screenshots(device_type: "tenInch") end
Verification
MANDATORY: Run these commands:
# Build APKs ./gradlew assembleDebug assembleAndroidTest # Start emulator # emulator -avd <avd_name> & # Run screenshots (with emulator running) bundle exec fastlane screenshots # Check output ls -la fastlane/metadata/android/en-US/images/phoneScreenshots/
Expected output:
- Screenshots appear in
fastlane/metadata/android/en-US/images/phoneScreenshots/ - Files named like
,01_home_en-US.png02_settings_en-US.png
Completion Criteria
-
dependency added totools.fastlane:screengrabapp/build.gradle.kts - Debug manifest (
) has required permissionsapp/src/debug/AndroidManifest.xml -
exists with at least one screenshotScreenshotTest.kt -
created for clean status barDemoModeRule.kt -
runs successfullybundle exec fastlane screenshots - Screenshots appear in
fastlane/metadata/android/en-US/images/phoneScreenshots/
Outputs
| Output | Location | Description |
|---|---|---|
| Screenshot test | | Test class for capturing screenshots |
| Demo mode rule | | Clean status bar helper |
| Debug manifest | | Permissions for screengrab |
| Screenshots | | Captured screenshots |
Troubleshooting
"Permission denied" errors
Cause: Debug manifest permissions not applied Fix: Clean and rebuild:
./gradlew clean assembleDebug assembleAndroidTest
"Test not found"
Cause: Wrong test class in Screengrabfile Fix: Ensure package name and class name match exactly
Screenshots are blank/black
Cause: Activity not fully loaded before screenshot Fix: Add
Thread.sleep() before Screengrab.screenshot()
Demo mode not working
Cause: Permission denied for DUMP permission Fix: Run on API 23+ emulator (demo mode requires API 23+)
Next Steps
After completing this skill:
- Customize
to capture your app's key screensScreenshotTest.kt - Run
to create feature graphic/devtools:android-store-listing - Run screenshots regularly to keep store listing updated