gplay-screenshot-automation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGoogle Play Screenshot Automation
Google Play 截图自动化
Use this skill for agent-driven screenshot workflows where Android screenshots are captured via emulators or connected devices, organized by locale and device type, and uploaded to Google Play via .
gplay本技能适用于由Agent驱动的截图工作流,可通过模拟器或连接的设备捕获Android截图,按语言区域和设备类型分类,并通过上传至Google Play。
gplayCurrent Scope
当前适用范围
- Screenshot capture via and Android test frameworks (Espresso, UI Automator).
adb shell screencap - Multi-device capture: phone, tablet, TV, Wear OS.
- Multi-locale capture with emulator locale switching.
- Device framing with third-party tools.
- Upload via or
gplay images upload.gplay sync import-images - CI/CD integration for fully automated pipelines.
- 通过和Android测试框架(Espresso、UI Automator)捕获截图。
adb shell screencap - 多设备捕获:手机、平板、电视、Wear OS设备。
- 支持模拟器切换语言区域,实现多语言区域截图。
- 借助第三方工具为截图添加设备框架。
- 通过或
gplay images upload上传截图。gplay sync import-images - 与CI/CD集成,实现全自动化流水线。
Defaults
默认配置
- Raw screenshots dir:
./screenshots/raw - Framed screenshots dir:
./screenshots/framed - Metadata dir (FastLane format):
./metadata
- 原始截图目录:
./screenshots/raw - 带框架的截图目录:
./screenshots/framed - 元数据目录(FastLane格式):
./metadata
1) Emulator Setup
1) 模拟器设置
Create emulators for each device type
为每种设备类型创建模拟器
bash
undefinedbash
undefinedPhone (Pixel 7, API 34)
手机(Pixel 7,API 34)
sdkmanager "system-images;android-34;google_apis;x86_64"
avdmanager create avd
--name "pixel7_api34"
--device "pixel_7"
--package "system-images;android-34;google_apis;x86_64"
--name "pixel7_api34"
--device "pixel_7"
--package "system-images;android-34;google_apis;x86_64"
sdkmanager "system-images;android-34;google_apis;x86_64"
avdmanager create avd
--name "pixel7_api34"
--device "pixel_7"
--package "system-images;android-34;google_apis;x86_64"
--name "pixel7_api34"
--device "pixel_7"
--package "system-images;android-34;google_apis;x86_64"
10-inch Tablet
10英寸平板
avdmanager create avd
--name "tablet10_api34"
--device "pixel_tablet"
--package "system-images;android-34;google_apis;x86_64"
--name "tablet10_api34"
--device "pixel_tablet"
--package "system-images;android-34;google_apis;x86_64"
avdmanager create avd
--name "tablet10_api34"
--device "pixel_tablet"
--package "system-images;android-34;google_apis;x86_64"
--name "tablet10_api34"
--device "pixel_tablet"
--package "system-images;android-34;google_apis;x86_64"
7-inch Tablet
7英寸平板
avdmanager create avd
--name "tablet7_api34"
--device "Nexus 7"
--package "system-images;android-34;google_apis;x86_64"
--name "tablet7_api34"
--device "Nexus 7"
--package "system-images;android-34;google_apis;x86_64"
undefinedavdmanager create avd
--name "tablet7_api34"
--device "Nexus 7"
--package "system-images;android-34;google_apis;x86_64"
--name "tablet7_api34"
--device "Nexus 7"
--package "system-images;android-34;google_apis;x86_64"
undefinedBoot emulators
启动模拟器
bash
emulator -avd pixel7_api34 -no-audio -no-window -gpu swiftshader_indirect &
adb wait-for-device
adb shell getprop sys.boot_completed # Wait until "1"For headless CI environments, always use .
-no-window -no-audio -gpu swiftshader_indirectbash
emulator -avd pixel7_api34 -no-audio -no-window -gpu swiftshader_indirect &
adb wait-for-device
adb shell getprop sys.boot_completed # 等待返回"1"在无界面CI环境中,务必使用参数。
-no-window -no-audio -gpu swiftshader_indirect2) Basic Capture with adb
2) 借助adb实现基础截图
Single screenshot
单张截图
bash
adb shell screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png ./screenshots/raw/en-US/phone/home.png
adb shell rm /sdcard/screenshot.pngbash
adb shell screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png ./screenshots/raw/en-US/phone/home.png
adb shell rm /sdcard/screenshot.pngHelper function for repeated captures
用于重复截图的辅助函数
bash
capture() {
local NAME="$1"
local LOCALE="$2"
local DEVICE_TYPE="$3"
local SERIAL="$4"
local OUTPUT_DIR="./screenshots/raw/$LOCALE/$DEVICE_TYPE"
mkdir -p "$OUTPUT_DIR"
adb -s "$SERIAL" shell screencap -p "/sdcard/$NAME.png"
adb -s "$SERIAL" pull "/sdcard/$NAME.png" "$OUTPUT_DIR/$NAME.png"
adb -s "$SERIAL" shell rm "/sdcard/$NAME.png"
echo "Captured $OUTPUT_DIR/$NAME.png"
}bash
capture() {
local NAME="$1"
local LOCALE="$2"
local DEVICE_TYPE="$3"
local SERIAL="$4"
local OUTPUT_DIR="./screenshots/raw/$LOCALE/$DEVICE_TYPE"
mkdir -p "$OUTPUT_DIR"
adb -s "$SERIAL" shell screencap -p "/sdcard/$NAME.png"
adb -s "$SERIAL" pull "/sdcard/$NAME.png" "$OUTPUT_DIR/$NAME.png"
adb -s "$SERIAL" shell rm "/sdcard/$NAME.png"
echo "Captured $OUTPUT_DIR/$NAME.png"
}Usage
使用示例
capture "home" "en-US" "phoneScreenshots" "emulator-5554"
capture "settings" "en-US" "phoneScreenshots" "emulator-5554"
capture "home" "en-US" "tenInchScreenshots" "emulator-5556"
undefinedcapture "home" "en-US" "phoneScreenshots" "emulator-5554"
capture "settings" "en-US" "phoneScreenshots" "emulator-5554"
capture "home" "en-US" "tenInchScreenshots" "emulator-5556"
undefined3) Test Framework Capture (Espresso / UI Automator)
3) 测试框架截图(Espresso / UI Automator)
For repeatable, state-driven screenshots, use Android instrumentation tests.
如需可重复、基于状态的截图,可使用Android插桩测试。
Espresso screenshot test
Espresso截图测试
kotlin
// app/src/androidTest/java/com/example/app/ScreenshotTest.kt
@RunWith(AndroidJUnit4::class)
class ScreenshotTest {
@get:Rule
val activityRule = ActivityScenarioRule(MainActivity::class.java)
@Test
fun captureHomeScreen() {
// Wait for content to load
onView(withId(R.id.main_content))
.check(matches(isDisplayed()))
takeScreenshot("home")
}
@Test
fun captureSearchScreen() {
onView(withId(R.id.search_button)).perform(click())
onView(withId(R.id.search_input)).perform(typeText("example"))
takeScreenshot("search")
}
private fun takeScreenshot(name: String) {
val bitmap = InstrumentationRegistry.getInstrumentation()
.uiAutomation.takeScreenshot()
val dir = File(
InstrumentationRegistry.getInstrumentation()
.targetContext.getExternalFilesDir(null),
"screenshots"
)
dir.mkdirs()
val file = File(dir, "$name.png")
file.outputStream().use {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, it)
}
}
}kotlin
// app/src/androidTest/java/com/example/app/ScreenshotTest.kt
@RunWith(AndroidJUnit4::class)
class ScreenshotTest {
@get:Rule
val activityRule = ActivityScenarioRule(MainActivity::class.java)
@Test
fun captureHomeScreen() {
// 等待内容加载完成
onView(withId(R.id.main_content))
.check(matches(isDisplayed()))
takeScreenshot("home")
}
@Test
fun captureSearchScreen() {
onView(withId(R.id.search_button)).perform(click())
onView(withId(R.id.search_input)).perform(typeText("example"))
takeScreenshot("search")
}
private fun takeScreenshot(name: String) {
val bitmap = InstrumentationRegistry.getInstrumentation()
.uiAutomation.takeScreenshot()
val dir = File(
InstrumentationRegistry.getInstrumentation()
.targetContext.getExternalFilesDir(null),
"screenshots"
)
dir.mkdirs()
val file = File(dir, "$name.png")
file.outputStream().use {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, it)
}
}
}Run tests and pull screenshots
运行测试并拉取截图
bash
undefinedbash
undefinedBuild and run instrumented tests
构建并运行插桩测试
./gradlew connectedAndroidTest
-Pandroid.testInstrumentationRunnerArguments.class=com.example.app.ScreenshotTest
-Pandroid.testInstrumentationRunnerArguments.class=com.example.app.ScreenshotTest
./gradlew connectedAndroidTest
-Pandroid.testInstrumentationRunnerArguments.class=com.example.app.ScreenshotTest
-Pandroid.testInstrumentationRunnerArguments.class=com.example.app.ScreenshotTest
Pull screenshots from device
从设备拉取截图
adb pull /sdcard/Android/data/com.example.app/files/screenshots/ ./screenshots/raw/en-US/phoneScreenshots/
undefinedadb pull /sdcard/Android/data/com.example.app/files/screenshots/ ./screenshots/raw/en-US/phoneScreenshots/
undefinedUI Automator for cross-app flows
用于跨应用流程的UI Automator
kotlin
@RunWith(AndroidJUnit4::class)
class UiAutomatorScreenshotTest {
private lateinit var device: UiDevice
@Before
fun setup() {
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
}
@Test
fun captureNotificationScreen() {
device.openNotification()
device.wait(Until.hasObject(By.pkg("com.android.systemui")), 3000)
takeScreenshot("notifications")
}
private fun takeScreenshot(name: String) {
val file = File(
InstrumentationRegistry.getInstrumentation()
.targetContext.getExternalFilesDir(null),
"screenshots/$name.png"
)
file.parentFile?.mkdirs()
device.takeScreenshot(file)
}
}kotlin
@RunWith(AndroidJUnit4::class)
class UiAutomatorScreenshotTest {
private lateinit var device: UiDevice
@Before
fun setup() {
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
}
@Test
fun captureNotificationScreen() {
device.openNotification()
device.wait(Until.hasObject(By.pkg("com.android.systemui")), 3000)
takeScreenshot("notifications")
}
private fun takeScreenshot(name: String) {
val file = File(
InstrumentationRegistry.getInstrumentation()
.targetContext.getExternalFilesDir(null),
"screenshots/$name.png"
)
file.parentFile?.mkdirs()
device.takeScreenshot(file)
}
}4) Multi-locale Capture
4) 多语言区域截图
Switch emulator locale via adb
通过adb切换模拟器语言区域
bash
set_locale() {
local SERIAL="$1"
local LOCALE="$2" # e.g. "de-DE"
local LANG="${LOCALE%%-*}" # e.g. "de"
local REGION="${LOCALE##*-}" # e.g. "DE"
adb -s "$SERIAL" shell "setprop persist.sys.locale ${LANG}-${REGION}"
adb -s "$SERIAL" shell "setprop persist.sys.language ${LANG}"
adb -s "$SERIAL" shell "setprop persist.sys.country ${REGION}"
adb -s "$SERIAL" shell "settings put system system_locales ${LANG}-${REGION}"
# Restart the app to pick up locale change
adb -s "$SERIAL" shell am force-stop com.example.app
adb -s "$SERIAL" shell am start -n com.example.app/.MainActivity
sleep 3
}bash
set_locale() {
local SERIAL="$1"
local LOCALE="$2" # 示例:"de-DE"
local LANG="${LOCALE%%-*}" # 示例:"de"
local REGION="${LOCALE##*-}" # 示例:"DE"
adb -s "$SERIAL" shell "setprop persist.sys.locale ${LANG}-${REGION}"
adb -s "$SERIAL" shell "setprop persist.sys.language ${LANG}"
adb -s "$SERIAL" shell "setprop persist.sys.country ${REGION}"
adb -s "$SERIAL" shell "settings put system system_locales ${LANG}-${REGION}"
# 重启应用以应用语言区域变更
adb -s "$SERIAL" shell am force-stop com.example.app
adb -s "$SERIAL" shell am start -n com.example.app/.MainActivity
sleep 3
}Capture across multiple locales
跨多语言区域截图
bash
#!/bin/bashbash
#!/bin/bashmulti-locale-capture.sh
multi-locale-capture.sh
SERIAL="emulator-5554"
PACKAGE="com.example.app"
LOCALES=("en-US" "de-DE" "fr-FR" "es-ES" "ja" "ko" "pt-BR" "zh-CN")
for LOCALE in "${LOCALES[@]}"; do
echo "Capturing locale: $LOCALE"
set_locale "$SERIAL" "$LOCALE"
mkdir -p "./screenshots/raw/$LOCALE/phoneScreenshots"
Capture each screen
for SCREEN in "home" "search" "settings" "profile"; do
adb -s "$SERIAL" shell screencap -p "/sdcard/$SCREEN.png"
adb -s "$SERIAL" pull "/sdcard/$SCREEN.png"
"./screenshots/raw/$LOCALE/phoneScreenshots/$SCREEN.png" adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png"
"./screenshots/raw/$LOCALE/phoneScreenshots/$SCREEN.png" adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png"
# Navigate to next screen (app-specific logic)
# adb -s "$SERIAL" shell input tap X Ydone
echo "Done: $LOCALE"
done
undefinedSERIAL="emulator-5554"
PACKAGE="com.example.app"
LOCALES=("en-US" "de-DE" "fr-FR" "es-ES" "ja" "ko" "pt-BR" "zh-CN")
for LOCALE in "${LOCALES[@]}"; do
echo "Capturing locale: $LOCALE"
set_locale "$SERIAL" "$LOCALE"
mkdir -p "./screenshots/raw/$LOCALE/phoneScreenshots"
捕获每个页面
for SCREEN in "home" "search" "settings" "profile"; do
adb -s "$SERIAL" shell screencap -p "/sdcard/$SCREEN.png"
adb -s "$SERIAL" pull "/sdcard/$SCREEN.png"
"./screenshots/raw/$LOCALE/phoneScreenshots/$SCREEN.png" adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png"
"./screenshots/raw/$LOCALE/phoneScreenshots/$SCREEN.png" adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png"
# 导航至下一个页面(应用特定逻辑)
# adb -s "$SERIAL" shell input tap X Ydone
echo "Done: $LOCALE"
done
undefinedUsing Espresso test arguments for locale
借助Espresso测试参数指定语言区域
bash
undefinedbash
undefinedRun screenshot tests with a specific locale
使用指定语言区域运行截图测试
./gradlew connectedAndroidTest
-Pandroid.testInstrumentationRunnerArguments.class=com.example.app.ScreenshotTest
-Pandroid.testInstrumentationRunnerArguments.locale=de-DE
-Pandroid.testInstrumentationRunnerArguments.class=com.example.app.ScreenshotTest
-Pandroid.testInstrumentationRunnerArguments.locale=de-DE
undefined./gradlew connectedAndroidTest
-Pandroid.testInstrumentationRunnerArguments.class=com.example.app.ScreenshotTest
-Pandroid.testInstrumentationRunnerArguments.locale=de-DE
-Pandroid.testInstrumentationRunnerArguments.class=com.example.app.ScreenshotTest
-Pandroid.testInstrumentationRunnerArguments.locale=de-DE
undefined5) Multi-device Capture
5) 多设备截图
Capture across phone, tablet, TV, and Wear
跨手机、平板、电视和Wear OS设备截图
bash
#!/bin/bashbash
#!/bin/bashmulti-device-capture.sh
multi-device-capture.sh
declare -A DEVICES=(
["phoneScreenshots"]="emulator-5554" # Pixel 7
["tenInchScreenshots"]="emulator-5556" # Pixel Tablet
["sevenInchScreenshots"]="emulator-5558" # Nexus 7
["tvScreenshots"]="emulator-5560" # Android TV
["wearScreenshots"]="emulator-5562" # Wear OS
)
LOCALE="en-US"
for DEVICE_TYPE in "${!DEVICES[@]}"; do
SERIAL="${DEVICES[$DEVICE_TYPE]}"
echo "Capturing $DEVICE_TYPE on $SERIAL"
mkdir -p "./screenshots/raw/$LOCALE/$DEVICE_TYPE"
for SCREEN in "home" "search" "settings"; do
adb -s "$SERIAL" shell screencap -p "/sdcard/$SCREEN.png"
adb -s "$SERIAL" pull "/sdcard/$SCREEN.png"
"./screenshots/raw/$LOCALE/$DEVICE_TYPE/$SCREEN.png" adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png" done
"./screenshots/raw/$LOCALE/$DEVICE_TYPE/$SCREEN.png" adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png" done
echo "Done: $DEVICE_TYPE"
done
undefineddeclare -A DEVICES=(
["phoneScreenshots"]="emulator-5554" # Pixel 7
["tenInchScreenshots"]="emulator-5556" # Pixel Tablet
["sevenInchScreenshots"]="emulator-5558" # Nexus 7
["tvScreenshots"]="emulator-5560" # Android TV
["wearScreenshots"]="emulator-5562" # Wear OS
)
LOCALE="en-US"
for DEVICE_TYPE in "${!DEVICES[@]}"; do
SERIAL="${DEVICES[$DEVICE_TYPE]}"
echo "Capturing $DEVICE_TYPE on $SERIAL"
mkdir -p "./screenshots/raw/$LOCALE/$DEVICE_TYPE"
for SCREEN in "home" "search" "settings"; do
adb -s "$SERIAL" shell screencap -p "/sdcard/$SCREEN.png"
adb -s "$SERIAL" pull "/sdcard/$SCREEN.png"
"./screenshots/raw/$LOCALE/$DEVICE_TYPE/$SCREEN.png" adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png" done
"./screenshots/raw/$LOCALE/$DEVICE_TYPE/$SCREEN.png" adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png" done
echo "Done: $DEVICE_TYPE"
done
undefined6) Device Framing
6) 设备框架添加
Use third-party tools to wrap raw screenshots in device frames for polished store listings.
使用第三方工具为原始截图添加设备框架,打造更专业的商店列表展示图。
Using frameit (from fastlane)
使用frameit(来自fastlane)
bash
gem install fastlanebash
gem install fastlanePlace Framefile.json alongside screenshots
在截图目录旁放置Framefile.json
cat > ./screenshots/raw/Framefile.json << 'EOF'
{
"device_frame_version": "latest",
"default": {
"keyword": { "font": "./fonts/SF-Pro-Display-Bold.otf" },
"title": { "font": "./fonts/SF-Pro-Display-Regular.otf" }
}
}
EOF
cd ./screenshots/raw && fastlane frameit
undefinedcat > ./screenshots/raw/Framefile.json << 'EOF'
{
"device_frame_version": "latest",
"default": {
"keyword": { "font": "./fonts/SF-Pro-Display-Bold.otf" },
"title": { "font": "./fonts/SF-Pro-Display-Regular.otf" }
}
}
EOF
cd ./screenshots/raw && fastlane frameit
undefinedUsing a custom framing script
使用自定义框架脚本
bash
#!/bin/bashbash
#!/bin/bashframe-screenshots.sh
frame-screenshots.sh
Requires ImageMagick
依赖ImageMagick
FRAME_IMAGE="./frames/pixel7_frame.png"
RAW_DIR="./screenshots/raw"
FRAMED_DIR="./screenshots/framed"
for LOCALE_DIR in "$RAW_DIR"//; do
LOCALE=$(basename "$LOCALE_DIR")
for TYPE_DIR in "$LOCALE_DIR"/; do
TYPE=$(basename "$TYPE_DIR")
mkdir -p "$FRAMED_DIR/$LOCALE/$TYPE"
for IMG in "$TYPE_DIR"*.png; do
NAME=$(basename "$IMG")
convert "$FRAME_IMAGE" "$IMG"
-gravity center -geometry +0+0 -composite
"$FRAMED_DIR/$LOCALE/$TYPE/$NAME" echo "Framed: $FRAMED_DIR/$LOCALE/$TYPE/$NAME" done done done
-gravity center -geometry +0+0 -composite
"$FRAMED_DIR/$LOCALE/$TYPE/$NAME" echo "Framed: $FRAMED_DIR/$LOCALE/$TYPE/$NAME" done done done
undefinedFRAME_IMAGE="./frames/pixel7_frame.png"
RAW_DIR="./screenshots/raw"
FRAMED_DIR="./screenshots/framed"
for LOCALE_DIR in "$RAW_DIR"//; do
LOCALE=$(basename "$LOCALE_DIR")
for TYPE_DIR in "$LOCALE_DIR"/; do
TYPE=$(basename "$TYPE_DIR")
mkdir -p "$FRAMED_DIR/$LOCALE/$TYPE"
for IMG in "$TYPE_DIR"*.png; do
NAME=$(basename "$IMG")
convert "$FRAME_IMAGE" "$IMG"
-gravity center -geometry +0+0 -composite
"$FRAMED_DIR/$LOCALE/$TYPE/$NAME" echo "Framed: $FRAMED_DIR/$LOCALE/$TYPE/$NAME" done done done
-gravity center -geometry +0+0 -composite
"$FRAMED_DIR/$LOCALE/$TYPE/$NAME" echo "Framed: $FRAMED_DIR/$LOCALE/$TYPE/$NAME" done done done
undefined7) Validate Before Upload
7) 上传前验证
Always validate screenshots before uploading:
bash
gplay validate screenshots --dir ./screenshots/framed --output tableCheck specific locale:
bash
gplay validate screenshots --dir ./screenshots/framed --locale en-US --output table上传前务必验证截图:
bash
gplay validate screenshots --dir ./screenshots/framed --output table检查特定语言区域:
bash
gplay validate screenshots --dir ./screenshots/framed --locale en-US --output table8) Upload to Google Play
8) 上传至Google Play
Option A: Upload via sync (FastLane directory structure)
选项A:通过同步上传(FastLane目录结构)
Organize screenshots in FastLane format:
metadata/
en-US/
images/
phoneScreenshots/
1_home.png
2_search.png
tenInchScreenshots/
1_home.png
de-DE/
images/
phoneScreenshots/
1_home.png
2_search.pngThen import:
bash
gplay sync import-images \
--package com.example.app \
--dir ./metadata按FastLane格式组织截图:
metadata/
en-US/
images/
phoneScreenshots/
1_home.png
2_search.png
tenInchScreenshots/
1_home.png
de-DE/
images/
phoneScreenshots/
1_home.png
2_search.png然后导入:
bash
gplay sync import-images \
--package com.example.app \
--dir ./metadataOption B: Upload individual images
选项B:上传单张图片
bash
EDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id')bash
EDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id')Upload phone screenshots
上传手机截图
gplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/home.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/home.png
gplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/search.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/search.png
gplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/home.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/home.png
gplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/search.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/search.png
Upload tablet screenshots
上传平板截图
gplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type tenInchScreenshots
--file ./screenshots/framed/en-US/tenInchScreenshots/home.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type tenInchScreenshots
--file ./screenshots/framed/en-US/tenInchScreenshots/home.png
gplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type tenInchScreenshots
--file ./screenshots/framed/en-US/tenInchScreenshots/home.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type tenInchScreenshots
--file ./screenshots/framed/en-US/tenInchScreenshots/home.png
Upload feature graphic
上传宣传图
gplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type featureGraphic
--file ./screenshots/framed/en-US/featureGraphic.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type featureGraphic
--file ./screenshots/framed/en-US/featureGraphic.png
gplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type featureGraphic
--file ./screenshots/framed/en-US/featureGraphic.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type featureGraphic
--file ./screenshots/framed/en-US/featureGraphic.png
Validate and commit
验证并提交
gplay edits validate --package com.example.app --edit $EDIT_ID
gplay edits commit --package com.example.app --edit $EDIT_ID
undefinedgplay edits validate --package com.example.app --edit $EDIT_ID
gplay edits commit --package com.example.app --edit $EDIT_ID
undefinedOption C: Upload as part of a release
选项C:作为版本发布的一部分上传
bash
gplay release \
--package com.example.app \
--track production \
--bundle app-release.aab \
--screenshots-dir ./metadata \
--release-notes @release-notes.jsonbash
gplay release \
--package com.example.app \
--track production \
--bundle app-release.aab \
--screenshots-dir ./metadata \
--release-notes @release-notes.jsonReplace existing screenshots
替换现有截图
Delete before uploading to replace:
bash
EDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id')上传前删除原有截图以实现替换:
bash
EDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id')Delete all existing phone screenshots for a locale
删除指定语言区域下所有现有手机截图
gplay images delete-all
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
gplay images delete-all
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
Upload new ones
上传新截图
gplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/home.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/home.png
gplay edits validate --package com.example.app --edit $EDIT_ID
gplay edits commit --package com.example.app --edit $EDIT_ID
undefinedgplay images upload
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/home.png
--package com.example.app
--edit $EDIT_ID
--locale en-US
--type phoneScreenshots
--file ./screenshots/framed/en-US/phoneScreenshots/home.png
gplay edits validate --package com.example.app --edit $EDIT_ID
gplay edits commit --package com.example.app --edit $EDIT_ID
undefined9) Full Automation Pipeline
9) 全自动化流水线
bash
#!/bin/bashbash
#!/bin/bashscreenshot-pipeline.sh
screenshot-pipeline.sh
End-to-end: boot emulators, capture, frame, validate, upload
端到端流程:启动模拟器、截图、添加框架、验证、上传
PACKAGE="com.example.app"
SERIAL="emulator-5554"
LOCALES=("en-US" "de-DE" "fr-FR" "es-ES" "ja")
RAW_DIR="./screenshots/raw"
METADATA_DIR="./metadata"
PACKAGE="com.example.app"
SERIAL="emulator-5554"
LOCALES=("en-US" "de-DE" "fr-FR" "es-ES" "ja")
RAW_DIR="./screenshots/raw"
METADATA_DIR="./metadata"
Step 1: Boot emulator
步骤1:启动模拟器
emulator -avd pixel7_api34 -no-audio -no-window -gpu swiftshader_indirect &
adb wait-for-device
adb -s "$SERIAL" shell "while [[ $(getprop sys.boot_completed) != '1' ]]; do sleep 1; done"
emulator -avd pixel7_api34 -no-audio -no-window -gpu swiftshader_indirect &
adb wait-for-device
adb -s "$SERIAL" shell "while [[ $(getprop sys.boot_completed) != '1' ]]; do sleep 1; done"
Step 2: Build and install app
步骤2:构建并安装应用
./gradlew assembleRelease
adb -s "$SERIAL" install -r app/build/outputs/apk/release/app-release.apk
./gradlew assembleRelease
adb -s "$SERIAL" install -r app/build/outputs/apk/release/app-release.apk
Step 3: Capture per locale
步骤3:按语言区域截图
for LOCALE in "${LOCALES[@]}"; do
set_locale "$SERIAL" "$LOCALE"
mkdir -p "$RAW_DIR/$LOCALE/phoneScreenshots"
for SCREEN in "home" "search" "settings" "profile"; do
adb -s "$SERIAL" shell screencap -p "/sdcard/$SCREEN.png"
adb -s "$SERIAL" pull "/sdcard/$SCREEN.png" "$RAW_DIR/$LOCALE/phoneScreenshots/$SCREEN.png"
adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png"
done
done
for LOCALE in "${LOCALES[@]}"; do
set_locale "$SERIAL" "$LOCALE"
mkdir -p "$RAW_DIR/$LOCALE/phoneScreenshots"
for SCREEN in "home" "search" "settings" "profile"; do
adb -s "$SERIAL" shell screencap -p "/sdcard/$SCREEN.png"
adb -s "$SERIAL" pull "/sdcard/$SCREEN.png" "$RAW_DIR/$LOCALE/phoneScreenshots/$SCREEN.png"
adb -s "$SERIAL" shell rm "/sdcard/$SCREEN.png"
done
done
Step 4: Organize into FastLane metadata structure
步骤4:整理为FastLane元数据结构
for LOCALE in "${LOCALES[@]}"; do
mkdir -p "$METADATA_DIR/$LOCALE/images/phoneScreenshots"
cp "$RAW_DIR/$LOCALE/phoneScreenshots/"*.png "$METADATA_DIR/$LOCALE/images/phoneScreenshots/"
done
for LOCALE in "${LOCALES[@]}"; do
mkdir -p "$METADATA_DIR/$LOCALE/images/phoneScreenshots"
cp "$RAW_DIR/$LOCALE/phoneScreenshots/"*.png "$METADATA_DIR/$LOCALE/images/phoneScreenshots/"
done
Step 5: Validate
步骤5:验证截图
gplay validate screenshots --dir "$METADATA_DIR" --output table
gplay validate screenshots --dir "$METADATA_DIR" --output table
Step 6: Upload
步骤6:上传至商店
gplay sync import-images --package "$PACKAGE" --dir "$METADATA_DIR"
gplay sync import-images --package "$PACKAGE" --dir "$METADATA_DIR"
Step 7: Kill emulator
步骤7:关闭模拟器
adb -s "$SERIAL" emu kill
echo "Screenshot pipeline complete."
undefinedadb -s "$SERIAL" emu kill
echo "Screenshot pipeline complete."
undefined10) CI/CD Integration
10) CI/CD集成
GitHub Actions
GitHub Actions
yaml
name: Screenshot Pipeline
on:
workflow_dispatch:
schedule:
- cron: '0 4 * * 1' # Weekly Monday 4am
jobs:
screenshots:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: AVD cache
uses: actions/cache@v4
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-api-34
- name: Create AVD
run: |
sdkmanager "system-images;android-34;google_apis;x86_64"
avdmanager create avd -n pixel7_api34 -d pixel_7 \
--package "system-images;android-34;google_apis;x86_64" --force
- name: Build app
run: ./gradlew assembleRelease
- name: Capture screenshots
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 34
target: google_apis
arch: x86_64
profile: pixel_7
script: ./scripts/capture-screenshots.sh
- name: Validate screenshots
run: gplay validate screenshots --dir ./metadata --output table
- name: Upload to Play Store
run: |
gplay sync import-images \
--package ${{ secrets.PACKAGE_NAME }} \
--dir ./metadata
env:
GPLAY_SERVICE_ACCOUNT: ${{ secrets.GPLAY_SERVICE_ACCOUNT_PATH }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: screenshots
path: ./screenshots/yaml
name: Screenshot Pipeline
on:
workflow_dispatch:
schedule:
- cron: '0 4 * * 1' # 每周一凌晨4点执行
jobs:
screenshots:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: AVD缓存
uses: actions/cache@v4
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-api-34
- name: 创建AVD
run: |
sdkmanager "system-images;android-34;google_apis;x86_64"
avdmanager create avd -n pixel7_api34 -d pixel_7 \
--package "system-images;android-34;google_apis;x86_64" --force
- name: 构建应用
run: ./gradlew assembleRelease
- name: 捕获截图
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 34
target: google_apis
arch: x86_64
profile: pixel_7
script: ./scripts/capture-screenshots.sh
- name: 验证截图
run: gplay validate screenshots --dir ./metadata --output table
- name: 上传至Play商店
run: |
gplay sync import-images \
--package ${{ secrets.PACKAGE_NAME }} \
--dir ./metadata
env:
GPLAY_SERVICE_ACCOUNT: ${{ secrets.GPLAY_SERVICE_ACCOUNT_PATH }}
- name: 上传产物
uses: actions/upload-artifact@v4
with:
name: screenshots
path: ./screenshots/Google Play Image Type Reference
Google Play图片类型参考
| Type | Usage |
|---|---|
| Phone screenshots (required, 2-8) |
| 7-inch tablet screenshots |
| 10-inch tablet screenshots |
| Android TV screenshots |
| Wear OS screenshots |
| Feature graphic (1024x500) |
| Promo graphic (180x120) |
| App icon (512x512, usually set in Console) |
| TV banner (1280x720) |
| 类型 | 用途 |
|---|---|
| 手机截图(必填,需2-8张) |
| 7英寸平板截图 |
| 10英寸平板截图 |
| Android TV截图 |
| Wear OS截图 |
| 宣传图(1024x500) |
| 促销图(180x120) |
| 应用图标(512x512,通常在控制台设置) |
| TV横幅图(1280x720) |
Agent Behavior
Agent行为规范
- Always confirm exact flags with before running commands.
--help - Use before uploading.
gplay validate screenshots - Prefer for bulk uploads over individual
gplay sync import-imagescalls.gplay images upload - When using individual uploads, always create an edit, upload, validate, then commit.
- Keep outputs deterministic: default to JSON for machine steps, for user review.
--output table - Use explicit long flags (,
--package,--edit,--locale,--type).--file - Verify emulator is fully booted () before capturing.
sys.boot_completed == 1 - For multi-locale workflows, always force-stop and relaunch the app after locale change.
- Validate screenshot counts (min 2 phone screenshots) before attempting upload.
- 运行命令前务必通过确认参数。
--help - 上传前使用验证截图。
gplay validate screenshots - 批量上传优先使用,而非多次调用
gplay sync import-images。gplay images upload - 单独上传时,务必先创建编辑任务、上传截图、验证,再提交。
- 保持输出确定性:机器执行步骤默认使用JSON格式,用户查看时使用。
--output table - 使用明确的长参数(,
--package,--edit,--locale,--type)。--file - 截图前验证模拟器是否完全启动()。
sys.boot_completed == 1 - 多语言区域工作流中,变更语言区域后务必强制停止并重启应用。
- 上传前验证截图数量(手机截图至少2张)。
Notes
注意事项
- Google Play requires PNG or JPEG format; PNG is recommended for quality.
- Maximum image file size is 8 MB per screenshot.
- Screenshot ordering on Play Store matches upload order.
- Use to verify uploaded images.
gplay images list - Use to clear screenshots before re-uploading.
gplay images delete-all - Always use to verify flags for the exact command.
--help
- Google Play要求截图为PNG或JPEG格式;推荐使用PNG以保证画质。
- 单张截图最大文件大小为8MB。
- Play商店中的截图顺序与上传顺序一致。
- 使用验证已上传的图片。
gplay images list - 重新上传前可使用清空现有截图。
gplay images delete-all - 务必使用确认命令的准确参数。
--help