Phase 9 — Automated store screenshots via Maestro on real simulator/emulator. Hides ads during capture.
Capture store screenshots by running the app on a real simulator/emulator with Maestro. Ads are hidden during capture via environment variable.
This is NOT image generation. Maestro physically controls the simulator:
Called by the orchestrator as Phase 9.
docs/harness/plans/YYYY-MM-DD-prd.md (screen structure)curl -Ls "https://get.maestro.mobile.dev" | bash)Store screenshots must NOT show ads. Before capturing, ensure the ad-hiding mechanism is in place.
Check src/features/ads/ui/AdBanner.tsx:
export function AdBanner({ size = BannerAdSize.ANCHORED_ADAPTIVE_BANNER }: IAdBannerProps) {
// Hide ads during screenshot capture
if (process.env.EXPO_PUBLIC_HIDE_ADS === 'true') return null;
return (
<BannerAd
unitId={getAdUnitId('BANNER')}
size={size}
requestOptions={{ requestNonPersonalizedAdsOnly: true }}
/>
);
}
If not present, add the EXPO_PUBLIC_HIDE_ADS check to:
AdBanner.tsx — banner componentuse-interstitial.ts — interstitial hook (skip show())use-rewarded.ts — rewarded hook (skip show())use-app-open-ad.ts — app open ad hook (skip)EXPO_PUBLIC_HIDE_ADS=true npx expo start --dev-client
Or if using expo run:*:
EXPO_PUBLIC_HIDE_ADS=true npx expo run:ios
EXPO_PUBLIC_HIDE_ADS=true npx expo run:android
Select 5-8 key screens from PRD for store listing:
# Check Maestro
which maestro && echo "MAESTRO=yes" || echo "MAESTRO=no"
# Check running simulators
xcrun simctl list devices 2>/dev/null | grep "Booted" || true
adb devices 2>/dev/null | grep -v "List" | grep "device" || true
If Maestro is NOT available: → Skip to Step 6 (Manual Fallback)
maestro/screenshots.yaml:
appId: com.company.app
---
# Wait for app to fully load
- waitForAnimationToEnd
# 1. First screen (login/onboarding/home)
- takeScreenshot: docs/harness/store-assets/ios/01-first
# 2. Navigate to home (if login needed, use test account)
- tapOn: "Home"
- waitForAnimationToEnd
- takeScreenshot: docs/harness/store-assets/ios/02-home
# 3. Core feature
- tapOn: "[Feature Button]"
- waitForAnimationToEnd
- takeScreenshot: docs/harness/store-assets/ios/03-feature
# 4. Detail screen
- tapOn:
index: 0
- waitForAnimationToEnd
- takeScreenshot: docs/harness/store-assets/ios/04-detail
# 5. Profile
- tapOn: "Profile"
- waitForAnimationToEnd
- takeScreenshot: docs/harness/store-assets/ios/05-profile
Customize the flow based on actual app screens and navigation. Use assertVisible to verify correct screen before capturing.
# iPhone 6.7" (Required — iPhone 15 Pro Max / iPhone 16 Pro Max)
maestro --device "iPhone 15 Pro Max" test maestro/screenshots.yaml
# iPhone 6.5" (Required — iPhone 11 Pro Max)
# Reuse 6.7" screenshots if similar resolution
iPad screenshots NOT needed (supportsTablet: false in app.config.ts).
# Phone (Required)
maestro test maestro/screenshots.yaml
docs/harness/store-assets/
├── ios/
│ ├── 01-first.png
│ ├── 02-home.png
│ ├── 03-feature.png
│ ├── 04-detail.png
│ └── 05-profile.png
├── android/
│ └── phone/
│ ├── 01-first.png
│ ├── 02-home.png
│ └── ...
├── icon.png # 512x512 (for Google Play)
├── feature_graphic.png # 1024x500 (for Google Play)
└── metadata/
└── ko-KR/
├── title.txt
├── short_description.txt
├── full_description.txt
└── release_notes.txt
If Maestro is not installed:
AskUserQuestion:
Maestro is not installed, so automatic screenshot capture is unavailable.
Please capture screenshots manually:
1. Run the app: EXPO_PUBLIC_HIDE_ADS=true npx expo start --dev-client
2. Navigate to each key screen
3. Take screenshots (Cmd+S in iOS Simulator, or device screenshot)
4. Save to docs/harness/store-assets/ios/ and android/phone/
Screens to capture:
1. [screen 1]
2. [screen 2]
...
Or install Maestro to automate:
curl -Ls "https://get.maestro.mobile.dev" | bash
Press Enter when screenshots are ready, or type "install" to install Maestro.
Create metadata files from PRD:
docs/harness/store-assets/metadata/ko-KR/title.txt:
[앱 이름] (30 chars max)
docs/harness/store-assets/metadata/ko-KR/subtitle.txt (iOS only):
[부제] (30 chars max)
docs/harness/store-assets/metadata/ko-KR/short_description.txt (Android):
[짧은 설명] (80 chars max)
docs/harness/store-assets/metadata/ko-KR/full_description.txt:
[전체 설명] (4000 chars max, includes key features, value proposition)
docs/harness/store-assets/metadata/ko-KR/keywords.txt (iOS only):
CRITICAL: iOS App Store keywords field has a 100-character limit INCLUDING commas. This field is one of the most important ASO (App Store Optimization) factors. Fill it to the MAXIMUM — generate keywords until the total exceeds 100 characters, then trim down.
Rules:
Process:
k1,k2,k3,...Example (coffee subscription tracker app):
구독관리,커피,정기배송,지출관리,가계부,알림,통계,지출분석,예산,subscription,coffee,tracker,monthly,bill,reminder,budget,spending
Count: 97 characters ✓ (uses full budget)
Bad example (too short):
커피,구독,관리
Count: 9 characters ✗ (wastes 91 characters of search opportunity)
docs/harness/store-assets/metadata/ko-KR/release_notes.txt:
[출시 노트]
AskUserQuestion:
Screenshots and metadata are ready. Please review:
Screenshots: docs/harness/store-assets/
Metadata: docs/harness/store-assets/metadata/ko-KR/
Checklist:
- [ ] Screenshots look clean (no ads visible)
- [ ] App name correct
- [ ] Description accurate
- [ ] Privacy policy URL: [URL from config]
Any changes needed? (Press Enter to proceed, or describe what to change)
docs/harness/store-assets/ — screenshots + metadatamaestro/screenshots.yaml — Maestro flowcurrent_phase: submit
next_role: rn-harness-submit