メインコンテンツまでスキップ

スクリーンショット撮影

UIテストを使用してiOS/iPadOSシミュレーターからApp Storeのスクリーンショットを直接キャプチャします。fastlane snapshotの代替です。

クイックスタート​

ascelerate screenshot init                  # Create config and helper in ascelerate/
ascelerate screenshot # Capture screenshots

AIコーディングエージェントでセットアップ​

キャプチャには、UIテストターゲット、スクリーンショットヘルパー、アプリ内のデモコンテンツ付きスクリーンショットモード、テスト本体、設定が必要です。コーディングエージェントがこれらをすべてセットアップできます:

ascelerate screenshot setup-prompt          # Print the setup instructions
ascelerate screenshot setup-prompt --copy # Copy them to the clipboard

指示を、プロジェクトで作業するコーディングエージェント(Claude Code、Codex、Cursor、Xcodeのコーディングアシスタントなど)に貼り付けます。指示はプロジェクトの現状(プロジェクト、スキーム、UIテストターゲット、ローカライズ、設定、ヘルパーのバージョン、インストール済みのシミュレーター)から始まるため、コマンドを再実行すると残りの作業がわかります。デバイスフレームも扱います。フレームはAppleのデザインリソース(Product Bezels)からご自身でダウンロードします。

--design を指定すると、代わりにデザインジェネレーターの指示を出力します。app-store-screenshots/ に置く小さなWebアプリで、フレーミングしたスクリーンショットを各言語の見出し付きApp Store画像に変換し、ascelerate apps media upload 用にエクスポートします(メディアを参照)。

コマンド​

実行​

ascelerate screenshot                       # Capture screenshots
ascelerate screenshot run # Same as above
ascelerate screenshot --json-events # Progress as JSON Lines events on stdout

常にカレントディレクトリの ascelerate/screenshot.yml を使用します。

--json-events は実行を追跡する他のツール向けです。stdoutには1行に1つのJSONオブジェクト(start、build、language、testing・passed・failed・collected などのステップを持つ device、すべての結果を含む finished)が出力され、読みやすい進捗はstderrに移ります。

初期化​

ascelerate screenshot init

ascelerate/ ディレクトリに ascelerate/screenshot.yml と ascelerate/ScreenshotHelper.swift の両方を作成します。書き込み前に確認を求めます(-y で省略できます)。既存のファイルは上書きしません。

ヘルパー作成​

ascelerate screenshot create-helper         # Generates ScreenshotHelper.swift
ascelerate screenshot create-helper -o CustomHelper.swift
ascelerate screenshot create-helper -o UITests/ScreenshotHelper.swift -y # Overwrite without asking

フレーミング​

ascelerate screenshot frame                    # Frame screenshots with device bezels

キャプチャしたスクリーンショットをデバイスベゼル画像でフレーミングします。設定の frameDevice と deviceBezel を使用します。スクリーンショットのキャプチャ後に独立して実行できます。

ドクター​

ascelerate screenshot doctor                   # Check config and environment
ascelerate screenshot doctor --json # The same as JSON

スクリーンショットの設定と環境を検証します:設定ファイル、プロジェクト/ワークスペースの存在、xcodebuildとsimctlの利用可能性、シミュレーターデバイス、ヘルパーファイルのバージョン、デバイスベゼルファイル、出力ディレクトリをチェックします。合格/不合格/警告のインジケーター付きチェックリストを表示します。--json を指定すると、設定(スキーム、デバイス、言語、出力ディレクトリ)と各チェックのステータス(pass、warn、fail)をJSONで出力します。

設定(ascelerate/screenshot.yml)​

workspace: MyApp.xcworkspace
# project: MyApp.xcodeproj # Use project instead of workspace
scheme: AppUITests
devices:
- simulator: iPhone 17 Pro Max
# frameDevice: true
# deviceBezel: ./bezels/iPhone 17 Pro Max.png
- simulator: iPad Pro 13-inch (M5)
# frameDevice: true
# deviceBezel: ./bezels/iPad Pro 13-inch (M5).png
languages:
- en-US
- de-DE
outputDirectory: ./screenshots
# framedOutputDirectory: ./screenshots/framed
clearPreviousScreenshots: true
eraseSimulator: false
localizeSimulator: true
overrideStatusBar: true
darkMode: false
disableAnimations: true
waitAfterBoot: 0
# waitAfterEraseAndReboot: 30 # 初回起動システム通知のための追加待機
# statusBarArguments: "--time '9:41' --dataNetwork wifi"
# testWithoutBuilding: true # Skip build, use existing xctestrun
# cleanBuild: false
# headless: false # Don't open simulator windows (DeviceHub / Simulator.app)
# helperPath: AppUITests/ScreenshotHelper.swift
# launchArguments:
# - -ui_testing
# configuration: Debug # Build configuration
# testplan: MyTestPlan # Xcode test plan name
# numberOfRetries: 0 # Retry failed languages (erase + reboot simulator)
# stopAfterFirstError: false # Stop all devices on first failure
# reinstallApp: false # Delete and reinstall app before tests
# disableAssetDownloads: false # mobileassetd を無効化(Siri/キーボード/ML アセットをダウンロードしない。オンデバイス ML アセットもブロック)
# xcargs: SWIFT_ACTIVE_COMPILATION_CONDITIONS=SCREENSHOTS

UIテストでの使用方法​

ScreenshotHelper.swift をUITestターゲットに追加します:

override func setUp() {
setupScreenshots(app)
app.launch()
}

func testScreenshots() {
screenshot("01-home")
app.buttons["Settings"].tap()
screenshot("02-settings")
}

アプリ側でスクリーンショットモードを検出できます:

if ProcessInfo.processInfo.arguments.contains("-ASC_SCREENSHOT") {
// Show demo data, hide debug UI, etc.
}

ヘルパーは disableAnimationsIfNeeded() 関数も提供しており、設定で disableAnimations が有効な場合にアニメーションを無効化できます:

override func setUp() {
setupScreenshots(app)
disableAnimationsIfNeeded()
app.launch()
}

iPhone Duo​

iPhone Duo シミュレーター(Xcode 27.1 以降)では、setHinge(.open) でデバイスを開き、setHinge(.closed) で折りたたみます。その後、システムがアプリを対応するディスプレイへ移すまで待機するため、次の screenshot() はそのディスプレイをキャプチャします。シミュレーターは常に折りたたまれた状態で起動します。

func testScreenshots() {
screenshot("01-folded")
setHinge(.open)
screenshot("02-unfolded")
}

開いた状態では多くのアプリが iPad と同じレイアウトになりますが、テストランナー内の UIDevice.current.userInterfaceIdiom は引き続き .phone を返します。テストで適切な処理を選ぶには、ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] == "iPhone19,4" を確認してください。

注意

ヒンジを操作する公式 API はありません。ヘルパーは Device Hub のヒンジスライダーと同じ入力イベントを送信するため、今後の Xcode のリリースで動作しなくなる可能性があります。

動作の仕組み​

  1. build-for-testing で一度ビルド(testWithoutBuilding: true の場合はスキップ)
  2. 各言語ごとに:すべてのシミュレーターを起動、iOS 26 の「Apple Intelligence の準備ができました」バナー(disableAssetDownloads が設定されていれば mobileassetd も)を抑止、ローカライズ、ステータスバーをオーバーライド
  3. 全デバイスで並行してテストを実行
  4. numberOfRetries が設定されていてデバイスが失敗した場合:失敗したシミュレーターをリセットし、再ローカライズ、再起動してテストを再実行
  5. デバイスごとのキャッシュから出力ディレクトリにスクリーンショットを収集
  6. デバイスベゼルでスクリーンショットをフレーミング(frameDevice が有効な場合)
  7. エラーはスキップして続行 — エラーログは出力に保存

出力​

screenshots/
├── en-US/
│ ├── iPhone 17 Pro Max-01-home.png
│ ├── iPhone 17 Pro Max-02-settings.png
│ └── iPad Pro 13-inch (M5)-01-home.png
└── de-DE/
└── ...

デバイスフレーミング​

Appleデバイスベゼルを使用して、キャプチャしたスクリーンショットをフレーミングします。

備考

デバイスベゼルはascelerateに含まれていません。Apple Product Bezelsからダウンロードしてください(Apple Developerアカウントが必要です)。ダウンロードは、現行の全デバイスのPNGベゼルを含むDMGファイルです。

セットアップ​

  1. Apple Design ResourcesからProduct Bezels DMGをダウンロード
  2. ベゼルPNGファイルをプロジェクト内のフォルダに展開(例:./bezels/)
  3. 設定でデバイスごとにフレーミングを有効化:
devices:
- simulator: iPhone 17 Pro Max
frameDevice: true
deviceBezel: ./bezels/iPhone 17 Pro Max.png
- simulator: iPad Pro 13-inch (M5)
frameDevice: false

1台のデバイスに複数のベゼルを指定できます。各スクリーンショットは、画面領域のサイズに該当するベゼルでフレーミングされます。たとえば iPhone Duo では、折りたたみ時のスクリーンショットには閉じた状態のベゼルが、開いた状態のスクリーンショットには開いた状態のベゼルが使われます:

devices:
- simulator: iPhone Duo
frameDevice: true
deviceBezel:
- ./bezels/iPhone Duo - Outer Closed Portrait.png
- ./bezels/iPhone Duo - Inner Open Landscape.png

横向きのスクリーンショットには、横向きのベゼルがリストにあればそれが、なければ回転した縦向きのベゼルが使われます。

出力​

フレーミングされたスクリーンショットは framedOutputDirectory に保存されます(デフォルト:{outputDirectory}/framed):

screenshots/framed/
├── en-US/
│ └── iPhone 17 Pro Max-01-home.png
└── de-DE/
└── ...

frameDevice: true のデバイスのみがフレーミングされます。フレーミングは screenshot run 中に各言語の後で自動的に実行されるか、screenshot frame で独立して実行できます。

オプション​

オプション説明
clearPreviousScreenshots収集前に言語フォルダをクリア(すべてのデバイスが成功した場合のみ)
eraseSimulator各言語の前にシミュレーターをリセット
localizeSimulator言語ごとにシミュレーターの言語/ロケールを設定
overrideStatusBarステータスバーをオーバーライド(9:41、フルバー、Wi-Fi)
statusBarArgumentsxcrun simctl status_bar のカスタム引数
darkModeシミュレーターでダークモードを有効化
disableAnimationsテスト中のアニメーションを無効化
waitAfterBootシミュレーター起動後の待機秒数(デフォルト: 0)
waitAfterEraseAndRebootシミュレーターが新鮮な状態のときの追加待機秒数 — 実行の最初の言語のとき、またはシミュレーターが消去されたとき(eraseSimulator: true または再試行による)。スクリーンショット撮影前に初回起動システム通知が表示される時間を確保します。(iOS 26 の「Apple Intelligence の準備ができました」バナーは自動的に抑止されるため、待機は不要です。)
testWithoutBuildingビルドをスキップし、既存のxctestrunファイルを使用
cleanBuildビルド前に clean を実行
headlessシミュレータのウィンドウを開かない(Xcode 27ではDeviceHub、それ以前はSimulator.app)
helperPathバージョンチェック用のScreenshotHelper.swiftへのパス
launchArgumentsアプリに渡す追加の起動引数
configurationビルド構成(例: Debug、Release)
testplanXcodeテストプラン名
numberOfRetries失敗した言語の再試行回数 — シミュレーターをリセットし、再ローカライズ、再起動してテストを再実行します。失敗したデバイスのみ再試行されます。再試行された結果はサマリーテーブルに表示されます。
stopAfterFirstError最初のエラー後にすべてのデバイスを停止
reinstallAppテスト前にアプリを削除して再インストール
disableAssetDownloadsシミュレーターの mobileassetd を無効化し、消去直後のシミュレーターに数 GB の Siri・キーボード・ML アセットがダウンロードされるのを止めます。一部のアプリが必要とするオンデバイス ML アセット(テキスト認識など)もブロックされるため、スクリーンショットがそれらに依存する場合はオフのままにしてください。消去でリセットされるため、準備のたびに適用されます。
xcargsxcodebuild に渡す追加の引数
frameDeviceこのデバイスのベゼルフレーミングを有効化(デバイスごと)
deviceBezelデバイスベゼルPNGファイルへのパス、またはパスのリスト。各スクリーンショットにはサイズに合うベゼルが使われます(デバイスごと)
framedOutputDirectoryフレーミングされたスクリーンショットの出力ディレクトリ(デフォルト:{outputDirectory}/framed)