关于 asc-shots-pipeline
此技能介绍使用 Xcode 命令行工具、AXe 和 `asc` 的 Agent 驱动型 App Store 截图流程,涵盖构建、截图、加框、审核及单语言或多语言上传。
主要功能
- 01在模拟器中构建并运行应用
- 02使用计划和 AXe 捕获界面
- 03通过固定版本的 Koubou 添加边框
- 04审核并批准截图集
- 05规划并应用多语言上传
- 06重新排列已上传截图
适用场景
- 01从模拟器捕获应用界面
- 02为商店页面准备带边框的图片
- 03上传前审核截图
- 04捕获并上传多种语言的截图
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rorkai/ app-store-connect-cli-skills --skill asc-shots-pipeline安装后在 Claude Code 中输入/asc-shots-pipeline确认已加载。
详细介绍
asc 截图流水线(xcodebuild -> AXe -> frame -> asc)
适用于由 Agent 驱动的截图工作流:使用 Xcode CLI 工具构建并启动应用,通过 AXe 驱动 UI,并使用 asc 上传截图。
当前范围
- 目前已实现:构建/运行、AXe 计划捕获、画框合成和上传。
- 可通过
asc screenshots list-frame-devices内置发现设备。 - asc CLI 中的本地截图自动化命令仍处于实验阶段。
- 画框固定使用 Koubou
0.20.0,以确保输出具有确定性。 - 反馈/问题: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"
如果应用包路径与默认位置不同,请使用 xcodebuild -showBuildSettings。
3) 使用 AXe(或 asc screenshots run)捕获截图
优先使用计划驱动的捕获方式:
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.20.0 进行画框。
运行画框步骤前,请先安装并验证:
pip install koubou==0.20.0
kou --version # expect 0.20.0
# After upgrading from 0.18.x, or if Koubou reports missing device frames,
# run once with network access:
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:
iphone-air(默认)、iphone-17-pro、iphone-17-pro-max、iphone-16e、iphone-17 - iPad:
ipad-pro-13、ipad-pro-11、ipad-air-13、ipad-air-11、ipad-mini - 其他:
mac、watch-series-11、watch-ultra-3、apple-tv
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
更改已上传截图集的顺序,无需重新上传。--ids 必须恰好列出该截图集中的每张截图一次,并按新顺序排列。如果命令读取截图集后又添加了截图,App Store Connect 会拒绝此次更新并保留更新前的顺序;请重新列出截图集并再次运行。其他人所做的仅调整顺序不会被检测到,并会被覆盖。
asc localizations screenshot-sets list --localization-id "LOC_ID" --include appScreenshots
asc screenshots list --set-id "SET_ID" --output table
asc screenshots reorder --set-id "SET_ID" --ids "THIRD_ID,FIRST_ID,SECOND_ID"
Agent 行为
- 运行命令前,始终使用
--help确认准确的标志。 - 由于截图命令变化很快,请使用
asc screenshots --help重新检查命令路径。 - 保持输出确定:机器处理步骤默认使用 JSON。
- 选择画框设备前,优先运行
asc screenshots list-frame-devices --output json。 - 上传前确保截图文件存在。
- 使用
asc screenshots reorder重新排列已上传截图集;切勿为了更改顺序而删除并重新上传截图。 - 使用明确的长标志(
--app、--output、--version-localization等)。 - 将截图本地自动化视为实验性功能,并在面向用户的交接说明中明确指出。
- 需要针对现有远程截图使用追加数量限制防护时,对经过审核的批次使用
asc screenshots plan/asc screenshots apply。 - 如果画框因版本错误而失败,请重新安装固定版本的 Koubou:
pip install koubou==0.20.0。 - 如果画框因缺少设备边框而失败,请在可访问网络时运行一次
kou setup-frames。
6)多语言环境截图(可选)
不要使用 xcrun simctl launch ... -e AppleLanguages 进行本地化设置。
-e 是环境变量模式,无法可靠地切换应用语言。
对于此流水线,请为每个 UDID 设置模拟器级区域默认值。这适用于
asc screenshots capture,该命令会在内部重新启动应用。
# Map each locale to a dedicated simulator UDID.
# (Create these simulators once with `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" # e.g. 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),请使用应用启动参数:
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..."
或者使用包含 locale:udid 配对的 xargs:
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"
# Step 1: Parallel capture with per-simulator locale defaults
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
# Step 2: Parallel framing
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
# Step 3: Generate review (single run, aggregates all locales)
asc screenshots review-generate \
--framed-dir "$FRAMED_DIR" \
--output-dir "./screenshots/review"
# Step 4: Upload (run per locale if needed)
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