스토어 스크린샷
목적
전환율이 높고, 앱과 일치하며, 스토어에서 요구하는 모든 슬롯에 맞는 스크린샷을 스크립트로 생성하여 UI가 변경될 때 몇 분 안에 다시 생성할 수 있게 합니다.
전제 조건
- 이번 릴리스의 UI가 최종 확정된 빌드.
- 앱 내에 결정론적 데모 데이터로 화면을 렌더링할 수 있는 캡처 하네스(Flutter golden/integration 테스트, XCUITest, Espresso/Compose 스크린샷 테스트 또는 Fastlane snapshot).
- Node.js 18+ 및 Chrome/Chromium (렌더링용,
scripts/에서npm i실행). - 업로드용 API 자격 증명 (
accounts-and-tax).
원칙
- 실제 캡처, 목업이 아님. 프레임 안의 모든 폰 화면은 출시된 앱의 캡처입니다. 다시 그리거나 "개선된" UI는 오해를 불러일으키며(가이드라인 2.3) 금방 구식이 됩니다.
- 숫자는 앱과 일치해야 함. 프레임에 "1,850 걸음" 또는 "12분"이 표시되면 앱이 데모 데이터에 대해 정확히 그 값을 생성해야 합니다. 하네스에서 데모 데이터를 생성하고 동일한 테스트에서 이를 단언(assert)하세요.
- 스크린샷이 앱이 수행하지 않는 작업을 보여주면 둘 중 하나를 수정하세요. 기능을 빌드하거나 프레임을 변경하세요. 갭을 출시하지 마십시오.
- 프레임에 다른 플랫폼을 표시하지 마세요. iOS에 Android 상태/내비게이션 바가 없어야 하며, Play에 Apple UI나 "App Store"가 없어야 합니다(2.3.10).
- 모든 로케일과 모든 기기에서 동일한 프레임 순서를 유지하세요.
기기 매트릭스
논리적 크기와 API 식별자가 포함된 전체 테이블: references/device-matrix.md. 요약 (Apple 스크린샷 사양 및 Play 미리보기 자산에서 확인):
| 슬롯 | 픽셀 (세로) | 필수 여부? |
|---|---|---|
| iPhone 대형 Dynamic Island (6.9") | 1320×2868 (1290×2796, 1260×2736도 가능) | 권장 기본 세트 |
| iPhone 중간 Dynamic Island | 1206×2622 또는 1179×2556 | 최소 1개 스크린샷 필수 |
| iPhone Duo 외부 디스플레이 | 1398×2034 | iOS 27.1 SDK 이상으로 빌드된 앱은 2027년 4월부터 필수; "iPhone Duo 최적화" 배지 추가 |
| iPhone Duo 내부 디스플레이 | 2007×2853 | 외부와 동일 |
| iPad 13" | 2064×2752 (또는 2048×2732) | 앱이 iPad에서 실행되는 경우에만 필수(iPhone 전용 앱은 제외) |
| Play 폰 | 예: 1080×1920 또는 1080×2160 (가로 320–3840 px, 긴 쪽 ≤ 2× 짧은 쪽) | 게시하려면 ≥ 2개 스크린샷; ≥ 1080 px에서 ≥ 4개 권장 |
| Play 7" 및 10" 태블릿 | 1080–7680 px, 9:16 또는 16:9 | 앱이 태블릿을 지원하는 경우 권장 |
| Play 기능 그래픽 | 1024×500 | 필수 |
| Play 아이콘 | 512×512, 32비트 PNG | 필수 |
Apple: 크기당 최대 10개; PNG 또는 JPEG; 알파 채널이나 투명도 없음. Play: 기기 유형당 최대 8개; JPEG 또는 24비트 PNG(알파 없음).
App Store 제품 페이지 크리에이티브 자산(최신 App Store Connect, "헤더 및 검색 결과" 탭):
- 헤더: 제품 페이지 상단에 있는 하나의 와이드 이미지, 3840×1646 또는 5244×2950. 선택 사항(없어도 제출 가능).
- 검색 결과: 5244×2950, 3840×2560 또는 1920×1280; 비어 있으면 스크린샷과 미리보기가 사용됩니다.
- 버전 페이지 또는 자산 라이브러리(크리에이티브 자산 업로드)를 통해 업로드한 다음 자산 찾아보기로 선택하세요. 라이브러리에 업로드된 자산은 나중에 사용할 수 있도록 유지됩니다.
- 디자인 참고: 스토어는 아이콘, 이름 및 Get 버튼을 헤더의 일부에 오버레이하므로 콘솔 미리보기에서 결과를 확인하세요.
- 이 슬롯은 버전이 검토 대기 중인 동안 잠깁니다. 제출하기 전에 추가하세요.
절차
1. 스토리 계획 (스토리보드 승인)
5–8개 프레임의 스토리보드를 작성합니다: 하나의 헤드라인(≤ 6단어), 하나의 지원 문구, 각각 하나의 캡처. 선택적 "파노라마" 레이아웃(번들 템플릿이 수행하는 작업): 프레임은 하나의 넓은 캔버스 조각이므로 모양이 프레임 가장자리를 가로질러 계속됩니다. 레이아웃이 무엇이든, 표시된 제안(무료 시작, 평가판)은 진실해야 합니다.
2. 실제 화면 캡처
대상 기기의 논리적 크기 × 픽셀 비율로 각 화면을 캡처하여 텍스트와 레이아웃이 해당 기기에 표시되는 것과 정확히 일치하도록 합니다. Flutter 예제(위젯/골든 테스트):
// 6.9\" iPhone: 440 x 956 논리적 포인트 @3x = 1320 x 2868 px
tester.view.physicalSize = const Size(1320, 2868);
tester.view.devicePixelRatio = 3.0;
await tester.pumpWidget(App(demo: DemoData.storeShots(locale: 'en')));
await tester.pumpAndSettle();
expect(find.text('1,850 steps'), findsOneWidget); // 헤드라인의 숫자는 실제입니다
await expectLater(find.byType(App), matchesGoldenFile('captures/en/iphone69/01_home.png'));
- 테스트에서 폰트를 로드하세요(그렇지 않으면 테스트 폰트가 상자를 렌더링합니다).
- 고정된 시계, 고정된 데모 데이터, 네트워크 없음.
- 디버그 배너를 숨기고 상태 표시줄을 깨끗한 상태로 설정하세요(또는 자르고 아무것도 그리지 마세요).
- 각 로케일을 별도로 캡처하세요. 현지화된 프레임 안에 영어 UI를 절대 배치하지 마십시오.
3. 프레임 합성
템플릿: templates/panorama.html, 렌더러: scripts/render.mjs.
cd scripts && npm i
node render.mjs ../templates/frames.example.json out/
렌더러는 모든 프레임을 하나의 캔버스(너비 = 프레임 수 × 프레임 너비)에 배치하고, 캡처를 로드하고, 글꼴을 기다린 다음, 구성의 모든 기기에 대해 정확한 픽셀 크기로 각 프레임 조각을 스크린샷합니다. 또한 1024×500 기능 그래픽을 렌더링합니다.
4. 확인
node check-images.mjs out/
다음의 경우 실패: 폴더 기기에 대한 잘못된 크기, 알파 채널 존재(PNG 컬러 유형 4/6 또는 tRNS 청크), 10개(Apple) / 8개(Play) 초과 파일, 번호 매기기 간격. 그런 다음 모든 이미지를 100% 확대하여 확인: 잘린 텍스트, 다른 플랫폼 UI, 플레이스홀더 문자열, 오래된 숫자.
5. API를 통한 업로드 (라이브 세트 교체 전 승인 필요)
- App Store Connect — scripts/upload-asc.mjs: 편집 가능한
appStoreVersion찾기 → 해당appStoreVersionLocalizations→screenshotDisplayType별appScreenshotSets→ 이전 스크린샷 삭제 → 예약 (POST /v1/appScreenshotswithfileName,fileSize) →uploadOperations에서 부분 업로드 → 커밋 (PATCHwithuploaded: true및 MD5sourceFileChecksum) → 세트의appScreenshots관계에서 순서 설정. 문서: 자산을 App Store Connect에 업로드. - Google Play — scripts/upload-play.mjs:
edits.insert→ 언어 및 이미지 유형별로edits.images.deleteall→ 순서대로edits.images.upload(phoneScreenshots,sevenInchScreenshots,tenInchScreenshots,featureGraphic) →edits.commit. 문서: edits.images.upload.
두 스크립트 모두 기본적으로 드라이 런(dry run)이며, 실제로 쓰려면 DRY_RUN=0을 설정하세요.
6. 다시 읽어보기
로케일 및 기기당 업로드된 자산 목록을 가져와서(두 API 모두) 로컬 폴더의 개수 및 순서와 비교합니다. Apple은 업로드를 비동기식으로 처리합니다. 모든 자산이 COMPLETE 전달 상태를 보고할 때까지 기다리세요.
사람의 승인이 필요한 결정 지점
스토리보드 및 헤드라인, 최종 시각적 방향, 라이브 스크린샷 세트 교체, Play 편집 커밋.
검증
check-images.mjs통과; 모든 필수 Apple 슬롯에 최소 하나의 이미지가 있습니다. Play에는 폰 샷과 기능 그래픽이 있습니다.- 다시 읽기 순서가 일치하고 실패한 자산 상태가 없습니다.
- 프레임의 각 숫자와 기능이 빌드에 대해 확인되었습니다.
일반적인 실수
- 6.9"만 업로드하고 필수 중간 Dynamic Island 슬롯을 누락하는 경우.
- 알파 채널로 내보낸 PNG(디자인 도구 및 투명 배경의 헤드리스 브라우저에서 흔히 발생 — 항상 불투명한 본문 배경을 설정).
- Play에서 6.9" 1320×2868 이미지를 사용하는 경우: 종횡비가 Play의 2:1 제한을 초과합니다. Play 전용 크기로 렌더링하세요.
- iPhone 전용 앱에 대한 iPad 스크린샷(필요 없음) — 또는 앱이 iPad에서 실행되는데 누락하는 경우.
- 앱에 없는 설정 행이나 결과를 표시하는 프레임.
- 헤드라인은 번역되었지만 캡처는 여전히 영어인 경우.