
























@@ -4,22 +4,30 @@ set -euo pipefail
44usage() {
55 cat <<'EOF'
66Usage:
7- scripts/android-screenshots.sh [--device <adb-serial>] [--locale en-US] [--skip-build] [--skip-install] [--dry-run]
7+ scripts/android-screenshots.sh [--device <adb-serial>] [--avd <name>] [--locale en-US] [--skip-build] [--skip-install] [--keep-emulator] [--dry-run]
8899Builds and installs the Play debug app, launches deterministic screenshot scenes,
1010and writes raw Google Play screenshots under:
1111 apps/android/fastlane/metadata/android/<locale>/images/phoneScreenshots/
12+13+If no ADB device is connected, pass --avd or set ANDROID_SCREENSHOT_AVD to boot
14+an emulator non-interactively for the screenshot run.
1215EOF
1316}
14171518ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
1619ANDROID_DIR="${ROOT_DIR}/apps/android"
1720LOCALE="en-US"
1821DEVICE="${ANDROID_SCREENSHOT_DEVICE:-}"
22+AVD="${ANDROID_SCREENSHOT_AVD:-}"
23+KEEP_EMULATOR="${ANDROID_SCREENSHOT_KEEP_EMULATOR:-0}"
1924SKIP_BUILD=0
2025SKIP_INSTALL=0
2126DRY_RUN=0
2227SCENES=(connect chat voice screen settings)
28+EMULATOR_PID=""
29+EMULATOR_LOG=""
30+STARTED_EMULATOR=0
23312432while [[ $# -gt 0 ]]; do
2533case "$1" in
@@ -30,6 +38,10 @@ while [[ $# -gt 0 ]]; do
3038 DEVICE="${2:-}"
3139shift 2
3240 ;;
41+ --avd)
42+ AVD="${2:-}"
43+shift 2
44+ ;;
3345 --locale)
3446 LOCALE="${2:-}"
3547shift 2
@@ -42,6 +54,10 @@ while [[ $# -gt 0 ]]; do
4254 SKIP_INSTALL=1
4355shift
4456 ;;
57+ --keep-emulator)
58+ KEEP_EMULATOR=1
59+shift
60+ ;;
4561 --dry-run)
4662 DRY_RUN=1
4763shift
@@ -58,6 +74,35 @@ while [[ $# -gt 0 ]]; do
5874esac
5975done
607677+cleanup_started_emulator() {
78+local stopped=0
79+80+if [[ "$STARTED_EMULATOR" != "1" || "$KEEP_EMULATOR" == "1" ]]; then
81+return
82+fi
83+if [[ -n "${ADB_BIN:-}" && -n "${ADB_SERIAL:-}" ]]; then
84+if "$ADB_BIN" -s "$ADB_SERIAL" emu kill >/dev/null 2>&1; then
85+ stopped=1
86+fi
87+fi
88+if [[ "$stopped" != "1" && -n "$EMULATOR_PID" ]]; then
89+kill "$EMULATOR_PID" >/dev/null 2>&1 || true
90+fi
91+}
92+93+cleanup_emulator_log() {
94+if [[ -n "$EMULATOR_LOG" && -f "$EMULATOR_LOG" ]]; then
95+ rm -f "$EMULATOR_LOG"
96+fi
97+}
98+99+cleanup() {
100+ cleanup_started_emulator
101+ cleanup_emulator_log
102+}
103+104+trap cleanup EXIT
105+61106adb_bin() {
62107if [[ -n "${ADB:-}" ]]; then
63108printf '%s\n' "$ADB"
@@ -77,22 +122,161 @@ adb_bin() {
77122return 127
78123}
79124125+emulator_bin() {
126+if [[ -n "${ANDROID_EMULATOR:-}" ]]; then
127+printf '%s\n' "$ANDROID_EMULATOR"
128+return
129+fi
130+if command -v emulator >/dev/null 2>&1; then
131+command -v emulator
132+return
133+fi
134+for sdk_root in "${ANDROID_HOME:-}" "${ANDROID_SDK_ROOT:-}" "$HOME/Library/Android/sdk"; do
135+if [[ -n "$sdk_root" && -x "$sdk_root/emulator/emulator" ]]; then
136+printf '%s\n' "$sdk_root/emulator/emulator"
137+return
138+fi
139+done
140+echo "Android emulator binary not found. Install the Android emulator or set ANDROID_EMULATOR." >&2
141+return 127
142+}
143+144+connected_devices() {
145+local adb="$1"
146+"$adb" devices | awk 'NR > 1 && $2 == "device" { print $1 }'
147+}
148+149+device_count() {
150+local devices="$1"
151+printf '%s\n' "$devices" | sed '/^$/d' | wc -l | tr -d ' '
152+}
153+154+wait_for_single_device() {
155+local adb="$1"
156+local timeout_seconds="${ANDROID_SCREENSHOT_EMULATOR_TIMEOUT_SECONDS:-180}"
157+local deadline=$((SECONDS + timeout_seconds))
158+local devices
159+local count
160+161+while (( SECONDS < deadline )); do
162+ devices="$(connected_devices "$adb")"
163+ count="$(device_count "$devices")"
164+if [[ "$count" == "1" ]]; then
165+printf '%s\n' "$devices"
166+return
167+fi
168+ sleep 2
169+done
170+171+echo "Timed out waiting for exactly one Android emulator device." >&2
172+"$adb" devices -l >&2 || true
173+return 1
174+}
175+176+wait_for_boot_completed() {
177+local adb="$1"
178+local serial="$2"
179+local timeout_seconds="${ANDROID_SCREENSHOT_EMULATOR_TIMEOUT_SECONDS:-180}"
180+local deadline=$((SECONDS + timeout_seconds))
181+local boot_completed
182+183+"$adb" -s "$serial" wait-for-device
184+while (( SECONDS < deadline )); do
185+ boot_completed="$("$adb" -s "$serial" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)"
186+if [[ "$boot_completed" == "1" ]]; then
187+"$adb" -s "$serial" shell input keyevent 82 >/dev/null 2>&1 || true
188+return
189+fi
190+ sleep 2
191+done
192+193+echo "Timed out waiting for Android emulator boot completion on ${serial}." >&2
194+return 1
195+}
196+197+wait_for_explicit_device() {
198+local adb="$1"
199+local serial="$2"
200+local timeout_seconds="${ANDROID_SCREENSHOT_DEVICE_TIMEOUT_SECONDS:-30}"
201+local deadline=$((SECONDS + timeout_seconds))
202+local state
203+204+while (( SECONDS < deadline )); do
205+ state="$("$adb" devices | awk -v serial="$serial" '$1 == serial { print $2 }')"
206+if [[ "$state" == "device" ]]; then
207+return
208+fi
209+ sleep 2
210+done
211+212+if [[ -n "$state" ]]; then
213+echo "Android device '${serial}' did not become usable within ${timeout_seconds}s; current adb state is '${state}'." >&2
214+else
215+echo "Android device '${serial}' was not found within ${timeout_seconds}s." >&2
216+fi
217+"$adb" devices -l >&2 || true
218+return 1
219+}
220+221+stabilize_device_for_screenshots() {
222+local adb="$1"
223+local serial="$2"
224+"$adb" -s "$serial" shell settings put global window_animation_scale 0 >/dev/null 2>&1 || true
225+"$adb" -s "$serial" shell settings put global transition_animation_scale 0 >/dev/null 2>&1 || true
226+"$adb" -s "$serial" shell settings put global animator_duration_scale 0 >/dev/null 2>&1 || true
227+}
228+229+boot_emulator() {
230+local adb="$1"
231+local avd="$2"
232+local emulator
233+local emulator_args
234+local extra_args
235+local serial
236+237+ emulator="$(emulator_bin)"
238+ EMULATOR_LOG="$(mktemp "${TMPDIR:-/tmp}/openclaw-android-screenshot-emulator.XXXXXX.log")"
239+echo "No connected Android device found. Booting AVD '${avd}'." >&2
240+ emulator_args=(-avd "$avd" -no-window -no-audio -no-boot-anim)
241+if [[ -n "${ANDROID_SCREENSHOT_EMULATOR_ARGS:-}" ]]; then
242+read -r -a extra_args <<<"$ANDROID_SCREENSHOT_EMULATOR_ARGS"
243+ emulator_args+=("${extra_args[@]}")
244+fi
245+"$emulator" "${emulator_args[@]}" >"$EMULATOR_LOG" 2>&1 &
246+ EMULATOR_PID="$!"
247+ STARTED_EMULATOR=1
248+249+ serial="$(wait_for_single_device "$adb")"
250+ wait_for_boot_completed "$adb" "$serial"
251+ stabilize_device_for_screenshots "$adb" "$serial"
252+ ADB_SERIAL="$serial"
253+}
254+80255resolve_device() {
81256local adb="$1"
257+local devices
258+local count
259+82260if [[ -n "$DEVICE" ]]; then
83-printf '%s\n' "$DEVICE"
261+ wait_for_explicit_device "$adb" "$DEVICE"
262+ stabilize_device_for_screenshots "$adb" "$DEVICE"
263+ ADB_SERIAL="$DEVICE"
84264return
85265fi
86-local devices
87- devices="$("$adb" devices | awk 'NR > 1 && $2 == "device" { print $1 }')"
88-local count
89- count="$(printf '%s\n' "$devices" | sed '/^$/d' | wc -l | tr -d ' ')"
266+ devices="$(connected_devices "$adb")"
267+ count="$(device_count "$devices")"
90268if [[ "$count" == "1" ]]; then
91-printf '%s\n' "$devices"
269+ stabilize_device_for_screenshots "$adb" "$devices"
270+ ADB_SERIAL="$devices"
92271return
93272fi
94273if [[ "$count" == "0" ]]; then
274+if [[ -n "$AVD" ]]; then
275+ boot_emulator "$adb" "$AVD"
276+return
277+fi
95278echo "No Android device or emulator is connected." >&2
279+echo "Start one manually, pass --device <adb-serial>, or pass --avd <name> to boot an emulator." >&2
96280else
97281echo "Multiple Android devices are connected. Pass --device <adb-serial>." >&2
98282fi
@@ -107,19 +291,23 @@ latest_play_debug_apk() {
107291}
108292109293OUTPUT_DIR="${ANDROID_DIR}/fastlane/metadata/android/${LOCALE}/images/phoneScreenshots"
110-ADB_SERIAL="${DEVICE:-<auto>}"
294+ADB_SERIAL=""
295+ADB_DISPLAY="${DEVICE:-<auto>}"
111296112297echo "Android screenshot output: ${OUTPUT_DIR}"
113298echo "Scenes: ${SCENES[*]}"
114-echo "ADB device: ${ADB_SERIAL}"
299+echo "ADB device: ${ADB_DISPLAY}"
300+if [[ -n "$AVD" ]]; then
301+echo "Fallback AVD: ${AVD}"
302+fi
115303116304if [[ "$DRY_RUN" == "1" ]]; then
117305echo "Dry run complete. No build, install, or capture commands were executed."
118306exit 0
119307fi
120308121309ADB_BIN="$(adb_bin)"
122-ADB_SERIAL="$(resolve_device "$ADB_BIN")"
310+resolve_device "$ADB_BIN"
123311mkdir -p "$OUTPUT_DIR"
124312rm -f "$OUTPUT_DIR"/*.png
125313此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。