asc-shots-pipeline

asc-shots-pipeline

熱門

使用 xcodebuild/simctl 進行建置與執行、透過 AXe 操作 UI,並結合 JSON 設定與計畫檔、基於 Koubou 的外框合成(`asc screenshots frame`)以及截圖上傳(`asc screenshots upload`),全面自動化 iOS 螢幕截圖工作流程。當使用者要求進行自動化截圖擷取、AXe 驅動的模擬器操作、外框合成或完整的截圖上傳流程時使用。

946星標
50分支
更新於 2026/7/31
SKILL.md
唯讀
名稱
asc-shots-pipeline
描述

使用 xcodebuild/simctl 進行建置與執行、透過 AXe 操作 UI,並結合 JSON 設定與計畫檔、基於 Koubou 的外框合成(`asc screenshots frame`)以及截圖上傳(`asc screenshots upload`),全面自動化 iOS 螢幕截圖工作流程。當使用者要求進行自動化截圖擷取、AXe 驅動的模擬器操作、外框合成或完整的截圖上傳流程時使用。

asc screenshots pipeline (xcodebuild -> AXe -> frame -> asc)

當需要由 Agent 驅動截圖工作流程時使用此 Skill。在此流程中,應用程式會透過 Xcode CLI 工具建置與啟動、利用 AXe 驅動 UI 操作,並使用 asc 完成截圖上傳。

當前支援範圍

  • 目前已實現功能:建置/執行、AXe 計畫擷取、外框合成以及上傳。
  • 內建裝置探索功能,可透過 asc screenshots list-frame-devices 查詢。
  • asc CLI 中的本機截圖自動化指令目前仍處於實驗階段。
  • 外框合成固定使用 Koubou 0.18.1 版本,以確保輸出結果確定一致。
  • 問題回報與建議:https://github.com/rorkai/App-Store-Connect-CLI/issues/new/choose

預設設定

  • 設定檔:.asc/shots.settings.json
  • 擷取計畫檔:.asc/screenshots.json
  • 原始截圖目錄:./screenshots/raw
  • 外框合成截圖目錄:./screenshots/framed
  • 預設外框裝置:iphone-air

1) 首先建立 JSON 設定檔

建立或更新 .asc/shots.settings.json

{
  "version": 1,
  "app": {
    "bundle_id": "com.example.app",
    "project": "MyApp.xcodeproj",
    "scheme": "MyApp",
    "simulator_udid": "booted"
  },
  "paths": {
    "plan": ".asc/screenshots.json",
    "raw_dir": "./screenshots/raw",
    "framed_dir": "./screenshots/framed"
  },
  "pipeline": {
    "frame_enabled": true,
    "upload_enabled": false
  },
  "upload": {
    "version_localization_id": "",
    "device_type": "IPHONE_65",
    "source_dir": "./screenshots/framed"
  }
}

若欲刻意跳過外框合成,請設定:

  • "frame_enabled": false
  • "upload.source_dir": "./screenshots/raw"

2) 在模擬器上建置並執行應用程式

使用 Xcode CLI 進行建置、安裝與啟動:

xcrun simctl boot "$UDID" || true

xcodebuild \
  -project "MyApp.xcodeproj" \
  -scheme "MyApp" \
  -configuration Debug \
  -destination "platform=iOS Simulator,id=$UDID" \
  -derivedDataPath ".build/DerivedData" \
  build

xcrun simctl install "$UDID" ".build/DerivedData/Build/Products/Debug-iphonesimulator/MyApp.app"
xcrun simctl launch "$UDID" "com.example.app"

若應用程式 Bundle 路徑與預設位置不同,請使用 xcodebuild -showBuildSettings 進行確認。

3) 使用 AXe 擷取截圖(或使用 asc screenshots run

建議優先使用計畫驅動(plan-driven)的擷取方式:

asc screenshots run --plan ".asc/screenshots.json" --udid "$UDID" --output json

在撰寫計畫檔時常用的 AXe 基礎操作指令:

axe describe-ui --udid "$UDID"
axe tap --id "search_field" --udid "$UDID"
axe type "wwdc" --udid "$UDID"
axe screenshot --output "./screenshots/raw/home.png" --udid "$UDID"

最簡 .asc/screenshots.json 範例:

{
  "version": 1,
  "app": {
    "bundle_id": "com.example.app",
    "udid": "booted",
    "output_dir": "./screenshots/raw"
  },
  "steps": [
    { "action": "launch" },
    { "action": "wait", "duration_ms": 800 },
    { "action": "screenshot", "name": "home" }
  ]
}

4) 使用 asc screenshots frame 為截圖套用外框

asc CLI 將外框合成固定使用 Koubou 0.18.1
在執行外框合成步驟前,請先完成安裝與驗證:

pip install koubou==0.18.1
kou --version  # 應顯示 0.18.1
# 若 Koubou 提示缺少裝置外框檔,請在連網狀態下執行一次:
kou setup-frames

請先查詢支援的外框裝置參數值:

asc screenshots list-frame-devices --output json

為單張截圖套用外框(預設為 iphone-air):

asc screenshots frame \
  --input "./screenshots/raw/home.png" \
  --output-dir "./screenshots/framed" \
  --device "iphone-air" \
  --output json

支援的 --device 參數值:

  • iphone-air(預設)
  • iphone-17-pro
  • iphone-17-pro-max
  • iphone-16e
  • iphone-17
  • mac

5) 使用 asc 上傳截圖

在上傳前先生成並審閱產出成品:

asc screenshots review-generate --framed-dir "./screenshots/framed" --output-dir "./screenshots/review"
asc screenshots review-open --output-dir "./screenshots/review"
asc screenshots review-approve --all-ready --output-dir "./screenshots/review"

對於已完成審閱的多語系截圖集,建議使用 plan/apply 流程,以便在上傳前先將遠端已有的截圖數量納入考量:

asc screenshots plan --app "APP_ID" --version "1.2.3" --review-output-dir "./screenshots/review" --output json
asc screenshots apply --app "APP_ID" --version "1.2.3" --review-output-dir "./screenshots/review" --confirm --output json

從設定的來源目錄進行上傳(啟用外框合成時預設為 ./screenshots/framed):

asc screenshots upload \
  --version-localization "LOC_ID" \
  --path "./screenshots/framed" \
  --device-type "IPHONE_65" \
  --output json

如有需要,可以在上傳前先列出或驗證:

asc screenshots sizes --output table
asc screenshots list --version-localization "LOC_ID" --output table

Agent 行為規範

  • 執行指令前,務必先以 --help 確認確切的旗標(flags)。
  • 由於截圖相關指令更新頻繁,請先透過 asc screenshots --help 再次確認指令路徑。
  • 保持輸出結果一致且可預測:機器處理步驟預設使用 JSON 格式。
  • 在選擇外框裝置前,優先執行 asc screenshots list-frame-devices --output json
  • 上傳前請確認截圖檔案確實存在。
  • 傳遞參數時請使用完整的長旗標(例如 --app--output--version-localization 等)。
  • 請將本機截圖自動化視為實驗性功能,並在交付給使用者的說明文件中特別註明。
  • 當需要針對遠端既有截圖計算數量上限防護(append-limit guardrails)時,針對已審閱的批次作業請使用 asc screenshots plan / asc screenshots apply
  • 若外框合成因版本錯誤而失敗,請重新安裝指定的 Koubou 版本:pip install koubou==0.18.1
  • 若外框合成因缺少裝置外框檔而失敗,請在連網狀態下執行一次 kou setup-frames

6) 多語系截圖擷取(選用)

切勿使用 xcrun simctl launch ... -e AppleLanguages 來處理在地化切換。
-e 屬於環境變數設定模式,無法可靠地切換應用程式語言。

在此自動化流程中,請針對各 UDID 設定模擬器層級的全域語系預設值。此方法可搭配 asc screenshots capture 運作(該指令會在內部重新啟動應用程式)。

# 將每個語系(locale)映射至專屬的模擬器 UDID。
# (請先透過 `xcrun simctl create` 建立這些模擬器。)
declare -A LOCALE_UDID=(
  ["en-US"]="UDID_EN_US"
  ["de-DE"]="UDID_DE_DE"
  ["fr-FR"]="UDID_FR_FR"
  ["ja-JP"]="UDID_JA_JP"
)

set_simulator_locale() {
  local UDID="$1"
  local LOCALE="$2"            # 例如 de-DE
  local LANG="${LOCALE%%-*}"   # de
  local APPLE_LOCALE="${LOCALE/-/_}" # de_DE

  xcrun simctl boot "$UDID" || true
  xcrun simctl spawn "$UDID" defaults write NSGlobalDomain AppleLanguages -array "$LANG"
  xcrun simctl spawn "$UDID" defaults write NSGlobalDomain AppleLocale -string "$APPLE_LOCALE"
}

for LOCALE in "${!LOCALE_UDID[@]}"; do
  UDID="${LOCALE_UDID[$LOCALE]}"
  echo "Capturing $LOCALE on $UDID..."
  set_simulator_locale "$UDID" "$LOCALE"

  xcrun simctl terminate "$UDID" "com.example.app" || true
  asc screenshots capture \
    --bundle-id "com.example.app" \
    --name "home" \
    --udid "$UDID" \
    --output-dir "./screenshots/raw/$LOCALE" \
    --output json
done

若您採手動啟動(非使用 asc screenshots capture),請傳遞應用程式啟動引數(launch arguments):

xcrun simctl launch "$UDID" "com.example.app" -AppleLanguages "(de)" -AppleLocale "de_DE"

7) 平行化執行以加速處理

每個模擬器 UDID 負責處理一個語系,並採平行化方式執行:

#!/bin/bash
# parallel-capture.sh

declare -A LOCALE_UDID=(
  ["en-US"]="UDID_EN_US"
  ["de-DE"]="UDID_DE_DE"
  ["fr-FR"]="UDID_FR_FR"
  ["ja-JP"]="UDID_JA_JP"
)

capture_locale() {
  local LOCALE="$1"
  local UDID="$2"
  local LANG="${LOCALE%%-*}"
  local APPLE_LOCALE="${LOCALE/-/_}"

  echo "Starting $LOCALE on $UDID"
  xcrun simctl boot "$UDID" || true
  xcrun simctl spawn "$UDID" defaults write NSGlobalDomain AppleLanguages -array "$LANG"
  xcrun simctl spawn "$UDID" defaults write NSGlobalDomain AppleLocale -string "$APPLE_LOCALE"
  xcrun simctl terminate "$UDID" "com.example.app" || true

  asc screenshots capture \
    --bundle-id "com.example.app" \
    --name "home" \
    --udid "$UDID" \
    --output-dir "./screenshots/raw/$LOCALE" \
    --output json

  echo "Completed $LOCALE"
}

for LOCALE in "${!LOCALE_UDID[@]}"; do
  capture_locale "$LOCALE" "${LOCALE_UDID[$LOCALE]}" &
done

wait
echo "All captures done. Now framing..."

或是搭配 xargs 使用 locale:udid 配對:

printf "%s\n" \
  "en-US:UDID_EN_US" \
  "de-DE:UDID_DE_DE" \
  "fr-FR:UDID_FR_FR" \
  "ja-JP:UDID_JA_JP" | xargs -P 4 -I {} bash -c '
    PAIR="{}"
    LOCALE="${PAIR%%:*}"
    UDID="${PAIR##*:}"
    LANG="${LOCALE%%-*}"
    APPLE_LOCALE="${LOCALE/-/_}"
    xcrun simctl boot "$UDID" || true
    xcrun simctl spawn "$UDID" defaults write NSGlobalDomain AppleLanguages -array "$LANG"
    xcrun simctl spawn "$UDID" defaults write NSGlobalDomain AppleLocale -string "$APPLE_LOCALE"
    xcrun simctl terminate "$UDID" "com.example.app" || true
    asc screenshots capture --bundle-id "com.example.app" --name "home" --udid "$UDID" --output-dir "./screenshots/raw/$LOCALE" --output json
  '

8) 完整多語系自動化流程範例

#!/bin/bash
# full-pipeline-multi-locale.sh

declare -A LOCALE_UDID=(
  ["en-US"]="UDID_EN_US"
  ["de-DE"]="UDID_DE_DE"
  ["fr-FR"]="UDID_FR_FR"
  ["es-ES"]="UDID_ES_ES"
  ["ja-JP"]="UDID_JA_JP"
)

DEVICE="iphone-air"
RAW_DIR="./screenshots/raw"
FRAMED_DIR="./screenshots/framed"

# 步驟 1:依據各模擬器設定語系預設值並進行平行化擷取
for LOCALE in "${!LOCALE_UDID[@]}"; do
  (
    UDID="${LOCALE_UDID[$LOCALE]}"
    LANG="${LOCALE%%-*}"
    APPLE_LOCALE="${LOCALE/-/_}"

    xcrun simctl boot "$UDID" || true
    xcrun simctl spawn "$UDID" defaults write NSGlobalDomain AppleLanguages -array "$LANG"
    xcrun simctl spawn "$UDID" defaults write NSGlobalDomain AppleLocale -string "$APPLE_LOCALE"
    xcrun simctl terminate "$UDID" "com.example.app" || true

    asc screenshots capture \
      --bundle-id "com.example.app" \
      --name "home" \
      --udid "$UDID" \
      --output-dir "$RAW_DIR/$LOCALE" \
      --output json
    echo "Captured $LOCALE"
  ) &
done
wait

# 步驟 2:平行化外框合成
for LOCALE in "${!LOCALE_UDID[@]}"; do
  (
    asc screenshots frame \
      --input "$RAW_DIR/$LOCALE/home.png" \
      --output-dir "$FRAMED_DIR/$LOCALE" \
      --device "$DEVICE" \
      --output json
    echo "Framed $LOCALE"
  ) &
done
wait

# 步驟 3:生成審閱資料(單次執行,彙整所有語系)
asc screenshots review-generate \
  --framed-dir "$FRAMED_DIR" \
  --output-dir "./screenshots/review"

# 步驟 4:上傳(視需要按語系分別執行)
for LOCALE in "${!LOCALE_UDID[@]}"; do
  asc screenshots upload \
    --version-localization "LOC_ID_FOR_$LOCALE" \
    --path "$FRAMED_DIR/$LOCALE" \
    --device-type "IPHONE_65" \
    --output json
done