App Storeのスクリーンショット生成をPython+UIテストで完全自動化する
TL;DR XCUITestでiPhone・iPadシミュレータのスクリーンショットを日英両言語で自動撮影 PythonのPillowでグラデーション背景+デバイスフレーム+テキストオーバーレイのマーケティング画像を生成 xcrun simctl io recordVideoでデモ動画も録画 App Store Connect APIで自動アップロード すべてをシェルスクリプト1本で実行可能 はじめに iOSアプリのApp Storeスクリーンショットは、iPhone 6.7インチ、iPad 12.9インチの各サイズを日英2言語分用意すると、それだけで12枚以上の画像を作る必要があります。 アプリを更新するたびに手作業でスクリーンショットを撮り直し、FigmaやPhotoshopでマーケティング画像を作り、App Store Connectに1枚ずつアップロードするのは手間がかかります。 本記事では、撮影 → 画像生成 → アップロードの全工程をコマンド一発で実行できるパイプラインの構築方法を解説します。 全体構成 capture_screenshots.sh ├── Step 1: シミュレータの準備(起動 + テスト画像追加) ├── Step 2: XCUITestでスクリーンショット撮影(JA/EN × iPhone/iPad) ├── Step 3: sipsでApple規定サイズにリサイズ ├── Step 4: Pillow でマーケティング画像を生成 ├── Step 5: xcrun simctl io でデモ動画を録画 └── Step 6: App Store Connect APIでアップロード Step 1: XCUITestでスクリーンショットを撮影する テストコードの設計 UIテスト用のテストクラスを作成します。ポイントは以下の3つです。 テスト画像の自動読み込み: TEST_IMAGE_PATH環境変数で画像パスを渡し、PHPickerを経由せずに画像を直接ロードします 言語切り替え: xcodebuild -testLanguageで設定された言語を-AppleLanguagesとしてアプリに渡します レビューダイアログの抑制: 起動引数で不要なダイアログを抑制します final class ScreenshotTests: XCTestCase { private var app: XCUIApplication! private let screenshotDir = ProcessInfo.processInfo.environment["SCREENSHOT_DIR"] ?? "/tmp/myapp_screenshots" override func setUpWithError() throws { continueAfterFailure = false app = XCUIApplication() // オンボーディングをスキップ、レビューダイアログを抑制 app.launchArguments += ["-hasCompletedOnboarding", "YES"] // テスト言語をアプリの言語設定に反映 let preferredLang = Locale.preferredLanguages.first ?? "ja" let langCode = preferredLang.components(separatedBy: "-").first ?? "ja" app.launchArguments += ["-AppleLanguages", "(\(langCode))", "-AppleLocale", langCode] // テスト用画像パスを環境変数で渡す app.launchEnvironment["TEST_IMAGE_PATH"] = "/path/to/test_sample.jpg" try FileManager.default.createDirectory( atPath: screenshotDir, withIntermediateDirectories: true ) } func testCaptureScreenshots() throws { app.launch() // 処理完了を待機 let backButton = app.buttons["back_button"] XCTAssertTrue(backButton.waitForExistence(timeout: 300)) sleep(2) // メイン画面のスクリーンショット saveScreenshot(name: "04_result") // 他の画面に遷移してスクリーンショットを撮る // ... backButton.tap() sleep(1) saveScreenshot(name: "01_camera") } private func saveScreenshot(name: String) { let screenshot = app.windows.firstMatch.screenshot() let attachment = XCTAttachment(screenshot: screenshot) attachment.name = name attachment.lifetime = .keepAlways add(attachment) let path = "\(screenshotDir)/\(name).png" try? screenshot.pngRepresentation.write(to: URL(fileURLWithPath: path)) } } saveScreenshotメソッドは、XCTestのXCTAttachmentとしてテスト結果に添付すると同時に、指定ディレクトリにPNGファイルとして保存します。ファイル名のプレフィックス(01_, 04_等)は、後のマーケティング画像生成で優先順位を制御するために使います。 ...
