使用 xcodebuild/simctl 负责建置与执行、AXe 驱动 UI 操作、JSON 设定与计划档、基于 Koubou 的外框合成(`asc screenshots frame`)以及截图上传(`asc screenshots upload`),来编排 iOS 自动化截图流程。当使用者要求自动截取截图、AXe 驱动的模拟器操作流程、外框合成或「从截图到上传」的完整工作流程时使用。
asc screenshots pipeline (xcodebuild -> AXe -> frame -> asc)
当需要以 Agent 驱动截图工作流程(使用 Xcode CLI 工具建置并启动 App、利用 AXe 操控 UI,并透过 asc 上传截图)时,请使用此 Skill。
目前支援范围
- 已实现功能:建置/执行、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) 在模拟器上建置并执行 App
使用 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"
若 App bundle 路径与预设位置不同,请使用 xcodebuild -showBuildSettings 查询。
3) 使用 AXe 截取截图(或使用 asc screenshots run)
建议优先使用基于计划(plan-driven)的截取方式:
asc screenshots run --plan ".asc/screenshots.json" --udid "$UDID" --output json
在撰写计划档时,常用的 AXe 基本操作(primitives):
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-proiphone-17-pro-maxiphone-16eiphone-17mac
5) 使用 asc 上传截图
在上传之前产生并预览(review)产出物:
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确认精确的 Flag。 - 由于截图相关指令更新迅速,请使用
asc screenshots --help再次确认指令路径。 - 保持输出的确定性:针对机器处理步骤,预设输出 JSON 格式。
- 在选择外框装置前,建议先执行
asc screenshots list-frame-devices --output json。 - 上传前请确保截图档案确实存在。
- 请使用完整的长参数(例如
--app、--output、--version-localization等)。 - 将本地截图自动化视为实验性功能,并在提交给使用者的交接说明中明确标注。
- 若需要在上传多张审查完的截图时考量远端现有截图数量防逾上限,请使用
asc screenshots plan/asc screenshots apply。 - 若外框合成因版本错误而失败,请重新安装指定版本的 Koubou:
pip install koubou==0.18.1。 - 若外框合成因缺少装置外框而失败,请在连网状态下执行一次
kou setup-frames。
6) 多语系截取(选填)
请勿使用 xcrun simctl launch ... -e AppleLanguages 来处理多语系语系设定。
-e 属于环境变量模式,无法稳定且可靠地切换 App 语言。
在此工作流程中,请为每个模拟器 UDID 设定全域的语系预设值。这种做法可配合 asc screenshots capture 正常运作(因为该指令会在内部重新启动 App)。
# 将每个语系映射到专属的模拟器 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 "正在 $UDID 上截取 $LOCALE..."
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 之外),请使用 App 启动参数(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 "正在 $UDID 上启动 $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
echo "已完成 $LOCALE"
}
for LOCALE in "${!LOCALE_UDID[@]}"; do
capture_locale "$LOCALE" "${LOCALE_UDID[$LOCALE]}" &
done
wait
echo "所有截图截取完成,开始合成外框..."
或者搭配 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 "已截取 $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 "已合成外框 $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






