name: asc-shots-pipeline
description: 使用xcodebuild/simctl进行构建运行,AXe进行UI操作,JSON设置和计划文件,基于Go的框架(asc screenshots frame)以及截图上传(asc screenshots upload)来协调iOS截图自动化。当用户请求自动化截图捕获、AXe驱动的模拟器流程、框架组合或截图到上传管道时使用。
asc screenshots pipeline (xcodebuild -> AXe -> frame -> asc)
使用此技能进行代理驱动的截图工作流,其中应用使用Xcode CLI工具构建和启动,UI使用AXe驱动,截图使用asc上传。
当前范围
- 现已实现:构建/运行、AXe计划捕获、框架组合和上传。
- 设备发现通过
asc screenshots list-frame-devices内置。 - 本地截图自动化命令在asc cli中是实验性的。
- 框架固定到Koubou
0.13.0以获得确定性输出。 - 反馈/问题:https://github.com/rudrankriyam/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.13.0。
在运行框架步骤之前安装并验证:
pip install koubou==0.13.0
kou --version # 期望 0.13.0
首先列出支持的框架设备值:
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-17
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"
从配置的源目录上传(当框架启用时默认./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
代理行为
- 在运行命令之前,始终使用
--help确认确切的标志。 - 重新检查命令路径,因为截图命令正在快速演进。
- 保持输出确定性:对机器步骤默认为JSON。
- 在选择框架设备之前,优先使用
asc screenshots list-frame-devices --output json。 - 确保截图文件在上传之前存在。
- 使用明确的长标志(如
--app、--output、--version-localization等)。 - 将截图本地自动化视为实验性,并在面向用户的交接笔记中指明。
- 如果框架因版本错误失败,重新安装固定的Koubou:
pip install koubou==0.13.0。
6) 多语言捕获(可选)
不要使用xcrun simctl launch ... -e AppleLanguages进行本地化。
-e是一个环境变量模式,不会可靠地切换应用语言。
对于此管道,使用每个UDID的模拟器范围内的区域设置默认值。这与asc screenshots capture一起工作,它在内部重新启动应用。
# 将每个语言映射到一个专用的模拟器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 "捕获 $LOCALE 在 $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 "开始 $LOCALE 在 $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 "完成 $LOCALE"
}
for LOCALE in "${!LOCALE_UDID[@]}"; do
capture_locale "$LOCALE" "${LOCALE_UDID[$LOCALE]}" &
done
wait
echo "所有捕获完成。现在框架..."
或使用带有locale:udid对的xargs:
printf "%s
" \
"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