mcpField
C
capturing-screenshots-and-screenrecord

capturing-screenshots-and-screenrecord

github.com/skydoves测试与质量33979 次安装22 周前更新
代码仓库

关于 capturing-screenshots-and-screenrecord

该技能指导 Android 开发者通过 ADB 获取 PNG 截图和 MP4 屏幕录制,并在 JUnit4 测试失败时收集截图与日志。重点说明二进制流完整性、录制限制及失败时采集模式。

主要功能

  1. 01通过 ADB 获取 PNG 截图
  2. 02录制设备屏幕为 MP4
  3. 03JUnit4 失败时收集截图与日志
  4. 04避免二进制输出损坏
  5. 05处理录制时长与停止限制

适用场景

  1. 01为失败的 CI 测试保存截图和 logcat
  2. 02从参考设备生成视觉回归截图
  3. 03录制 QA 复现视频并关联日志
  4. 04修复 Windows CI 中损坏的截图流

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/skydoves/android-testing-skills --skill capturing-screenshots-and-screenrecord

安装后在 Claude Code 中输入/capturing-screenshots-and-screenrecord确认已加载。

详细介绍

截取屏幕截图和录屏——用于测试的视觉产物

此技能介绍如何通过 adb 从设备截取 PNG 屏幕截图和录制 MP4 视频,以及如何使用 JUnit4 TestWatcher 模式在测试失败时捕获内容。本节不涉及 Android Studio 的屏幕截图工具、Compose captureToImage(),或第三方串流工具(scrcpy/Vysor)。

何时使用此技能

  • 不稳定的 CI 测试需要在失败时截取屏幕截图并转储 logcat。
  • 团队需要从参考设备生成视觉回归测试的黄金截图。
  • QA 需要录制一段 30 s 的问题复现视频,附在缺陷报告中。
  • 开发者运行 adb shell screencap /sdcard/out.png 生成了损坏的文件——缺少 -p 标志导致写入的是原始 RGBA,而不是 PNG。
  • Windows CI Agent 收到的屏幕截图存在 CRLF 损坏——解决方法是 adb exec-out screencap -p。

何时不使用此技能

  • 使用 captureToImage() / Roborazzi / Paparazzi 的 Compose 层屏幕截图测试。这些属于单元测试机制,应使用 Compose 套件,而不是 ADB。
  • 持续实时镜像设备(演示、展示)。请使用 scrcpy 或 Vysor——screenrecord 无法串流。
  • 先操作设备(点击、按键事件)。请使用 ../../control/injecting-input-and-state/SKILL.md。
  • 常规拉取文件(不只是屏幕截图)。请使用 ../../transfer/extracting-test-artifacts/SKILL.md。

前提条件

  • adb get-state 返回 device。请参阅 ../../devices/connecting-to-devices/SKILL.md。
  • 使用 screenrecord:设备 API 19+(Android 4.4)——screenrecord 是在 KitKat 中加入的。
  • 使用 Wear OS 的 screenrecord:不支持。该工具会拒绝执行(developer.android.com/tools/adb#screenrecord)。
  • API 30+ 上写入 /sdcard/:需遵循分区存储规则;shell 用户仍可通过 FUSE/sdcardfs 访问,但应用私有写入会转到 /sdcard/Android/data/<pkg>/。

screencap——PNG 屏幕截图

“screencap 命令是一个 shell 工具,用于截取设备显示内容。”——developer.android.com/tools/adb#screencap

screencap [-h] [-p] [-d <displayId>] [<path-on-device>]
标志含义
(无标志)将原始 RGBA 帧缓冲区写入文件。不是 PNG。
-p编码为 PNG。向主机的标准输出流式传输时必须使用。
-d <displayId>捕获指定的逻辑显示屏(多显示屏设备)。
-h帮助。

三种惯用调用方式:

# 1. Save to device, then pull (good when the test continues running).
adb shell screencap -p /sdcard/screen.png
adb pull /sdcard/screen.png ./screen.png

# 2. Stream PNG bytes back to host without an intermediate file.
adb exec-out screencap -p > screen.png

# 3. Multi-display capture: external display + main.
adb shell screencap -p -d 0 /sdcard/main.png
adb shell screencap -p -d 1 /sdcard/external.png
exec-out 与 shell——二进制数据干净传输的陷阱

adb shell 默认会建立 PTY,在某些主机上(尤其是 Windows)会在输出时将 \n 转换为 \r\n。对于二进制流(PNG、MP4、tar 归档),这会损坏文件。adb exec-out 是可干净传输二进制数据的标准输出方式。

操作建议——在 Windows 上,流式传输时切勿使用 adb shell screencap -p > out.png。请始终使用:

adb exec-out screencap -p > out.png

如果先将文件写入设备,再拉取到主机,则不会出现此问题(adb pull 可干净传输二进制数据)。

screenrecord——MP4 录屏

“screenrecord 命令是一个 shell 工具,用于录制运行 Android 4.4(API 级别 19)及更高版本的设备显示内容。该工具会将屏幕活动录制为 MPEG-4 文件。”——developer.android.com/tools/adb#screenrecord

screenrecord [--size WIDTHxHEIGHT] [--bit-rate RATE] [--time-limit TIME]
             [--rotate] [--bugreport] [--verbose] <path-on-device>
标志原文含义(developer.android.com/tools/adb#screenrecord)
--help“显示命令语法和选项”。
--size WxH“设置视频尺寸。默认值为设备的原生显示分辨率(如果支持),否则为 1280x720。”
--bit-rate R“设置视频的比特率,单位为兆比特每秒。默认值为 20Mbps。”
--time-limit T“设置最长录制时间,单位为秒。默认值和最大值均为 180(3 分钟)。”
--rotate“将输出旋转 90 度。此功能为实验性功能。”
--bugreport嵌入用于缺陷报告附件的文本帧信息 / 时间戳叠加层。
--verbose“在命令行屏幕上显示日志信息。”
硬性限制(原文)
  • “视频文件中不会录制音频。”
  • “运行 Wear OS 的设备不支持视频录制。”
  • “某些设备可能无法以原生显示分辨率录制。如果屏幕录制遇到问题,请尝试使用较低的屏幕分辨率。”
  • “录制期间不支持旋转屏幕。”
  • 默认和最长时限为 180 s。若要捕获更长的场景,请串联多次调用并在事后合并,或使用 scrcpy。
没有流式传输标志 — 此限制

screenrecord 会将单个 MP4 写入设备端路径;它不会将内容流式传输到 stdout。要进行实时镜像(演示、展示),请使用 scrcpy 或 Vysor(不属于此技能的范围——两者都会完全绕过 screenrecord)。

输出路径
路径使用时机
/sdcard/run.mp4默认路径。用户可见的视频。API 30+ 适用分区存储规则,但 shell 用户可通过 FUSE/sdcardfs 访问。
/data/local/tmp/run.mp4当测试应用必须在 SD 卡挂载前生成输出,或要避免触碰公共存储时使用。shell 始终可以拉取此文件。
提前停止

screenrecord 会持续运行,直到 --time-limit 到期或收到 SIGINT。从交互式 shell 中按 Ctrl+C。从脚本中向设备端进程发送信号:

adb shell screenrecord --time-limit 180 /sdcard/run.mp4 &
REC=$!
# … run instrumentation; on failure, send SIGINT to the on-device process …
adb shell pkill -INT screenrecord
wait $REC
adb pull /sdcard/run.mp4 ./run.mp4
--bugreport 叠加层

--bugreport 会为每一帧添加帧信息和时间戳叠加层,这对于 QA 复现很有用,可使错误报告中的时间戳与 logcat 对齐。搭配 adb logcat -v threadtime,year,UTC,即可关联帧编号和日志行(参见 ../../observability/extracting-logs-with-logcat/SKILL.md)。

失败时捕获模式(JUnit4 TestWatcher)

标准模式:TestRule 或 TestWatcher 在测试失败时触发 failed(),运行 screencap + logcat -d,并将生成的文件拉取到每个测试各自的目录中。

class CaptureOnFailureRule(private val outputDir: File) : TestWatcher() {
    override fun failed(e: Throwable, description: Description) {
        val testName = "${description.className}.${description.methodName}"
        val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
        val target = File(outputDir, testName).apply { mkdirs() }

        // PNG screenshot
        device.executeShellCommand("screencap -p /sdcard/fail.png")
        device.executeShellCommand("logcat -d -v threadtime").let { log ->
            File(target, "logcat.txt").writeText(log)
        }
        // The test process can pull /sdcard/fail.png via Context.getExternalFilesDir
        // or push through TestStorageService — see ../../transfer/extracting-test-artifacts/SKILL.md.
    }
}

CI 脚本中的主机端等效做法(完整版本参见 ../../automation/scripting-adb-for-ci/SKILL.md):

set +e
./gradlew connectedDebugAndroidTest
RC=$?
set -e

if [ "$RC" -ne 0 ]; then
  mkdir -p artifacts
  adb shell screencap -p /sdcard/fail.png
  adb pull /sdcard/fail.png artifacts/fail.png
  adb logcat -d -v threadtime > artifacts/logcat.txt
  adb logcat -d -b crash      -v threadtime > artifacts/crash.txt
fi
exit $RC

此操作仅在失败时捕获设备的最后一帧以及 logcat 转储(绿色运行时可节省 CI 存储空间)。如需更丰富的逐测试文件路由,建议使用 AndroidX TestStorageService API — 参见 ../../transfer/extracting-test-artifacts/SKILL.md。

模式

模式:错误做法 — screencap 未加 -p
# WRONG
adb shell screencap /sdcard/out.png
file /sdcard/out.png      # → "data" (not a PNG)
# WRONG because: without -p, screencap writes a raw RGBA framebuffer (header + naked pixel
# bytes), not a PNG. Image viewers refuse to open it. The .png extension is misleading.
# RIGHT
adb shell screencap -p /sdcard/out.png
adb pull /sdcard/out.png ./out.png
模式:错误做法 — 在 Windows 上运行 adb shell screencap -p > out.png
# WRONG (on Windows / certain CI hosts)
adb shell screencap -p > out.png
# WRONG because: `adb shell` allocates a PTY and translates LF to CRLF on stdout. For
# binary streams (PNG bytes) this corrupts the file.
# RIGHT (binary-clean stdout)
adb exec-out screencap -p > out.png
模式:长时间捕获超过 3 分钟上限
# WRONG — assumes a single screenrecord can capture 10 minutes
adb shell screenrecord --time-limit 600 /sdcard/run.mp4
# WRONG because: --time-limit is capped at 180. The utility silently truncates to 180.
# RIGHT — chain
for i in 1 2 3 4; do
  adb shell screenrecord --time-limit 180 /sdcard/run-$i.mp4
done
adb pull /sdcard/run-1.mp4 ./
adb pull /sdcard/run-2.mp4 ./
adb pull /sdcard/run-3.mp4 ./
adb pull /sdcard/run-4.mp4 ./
# Concatenate with ffmpeg if needed:
# ffmpeg -f concat -i list.txt -c copy out.mp4

(或者改用 scrcpy 进行无限时长捕获。)

模式:用于 QA 复现的错误报告叠加层
adb shell screenrecord --bugreport --time-limit 60 \
  --bit-rate 8000000 --size 720x1280 /sdcard/repro.mp4
# Each frame has a frame-info + timestamp overlay aligning with logcat -v threadtime,year,UTC.
adb pull /sdcard/repro.mp4 ./repro.mp4
adb logcat -d -v threadtime,year,UTC > repro-logcat.txt

强制规则

  • 必须为 screencap 传入 -p 以输出 PNG。否则文件将是原始 RGBA 格式,无法在图像查看器中使用。
  • 必须在流式捕获时优先使用 adb exec-out screencap -p > out.png,而不是 adb shell screencap -p > out.png;尤其是在 Windows 或任何可能应用 \n → \r\n 转换的 CI 主机上。
  • 必须将 screenrecord --time-limit 视为最长不超过 180 s。任何更长的捕获都需要串联操作或使用 scrcpy。
  • 必须使用 adb shell pkill -INT screenrecord 停止 screenrecord(不能从主机端使用 kill -9)——SIGKILL 会导致 MP4 未完成封装而无法播放。
  • 不得假定 screenrecord 会捕获音频——它不会(developer.android.com/tools/adb#screenrecord)。
  • 不得在 Wear OS 上使用 screenrecord——不受支持。
  • **优先:**仅在失败时捕获(而非每次运行都捕获)。这样可节省 CI 存储空间,并直接定位到失败的测试。
  • **优先:**每次使用 screenrecord --bugreport 时,都搭配同时捕获的 logcat -v threadtime,year,UTC 转储。否则叠加层很难与日志关联。

验证

  • 执行 adb shell screencap -p /sdcard/out.png && adb pull /sdcard/out.png 后,file ./out.png 报告 PNG image data。
  • 在 Windows CI 上,通过 adb exec-out screencap -p > out.png 流式传输屏幕截图(不会因 \r\n 导致损坏)。
  • 仅当测试退出代码非零时,CI 才会捕获 screencap 和 logcat -d。
  • 任何脚本中都不存在 screenrecord --time-limit <N> 且 N > 180 的情况。
  • 不对 screenrecord 进程执行 kill -9——只使用 pkill -INT screenrecord,以便完成 MP4 文件。
  • CI 工件归档包含以 Class.method 命名的各测试子目录。

参考资料

  • developer.android.com/tools/adb#screencap — screencap 语法、-p 标志、exec-out 流式传输。
  • developer.android.com/tools/adb#screenrecord — screenrecord 语法、标志、硬性限制(“不录制音频”、180 秒上限、不支持 Wear OS、录制期间不能旋转)。
  • developer.android.com/tools/adb#shellcommands — 引号处理,以及 exec-out 与 shell 的区别。
  • developer.android.com/training/testing/instrumented-tests/stability — 插桩测试中的屏幕截图与复现规范。
  • 研究笔记 tasks/research/A2-adb-shell-commands.md — 完整的 screencap / screenrecord 标志表。
  • 研究笔记 tasks/research/A3-adb-observability-automation.md — 失败时捕获的 CI 模式;使用 exec-out 的理由。
  • 同级技能:../../architecture/understanding-adb-architecture/SKILL.md — 服务端 / 守护进程 / adb shell 与 adb exec-out。
  • 同级技能:../../devices/connecting-to-devices/SKILL.md — adb get-state、多设备定向。
  • 同级技能:../../devices/connecting-over-wifi/SKILL.md — 用于无线捕获的 adb pair。
  • 同级技能:../../apps/installing-and-managing-apps/SKILL.md — 安装 APK,以便针对其进行捕获。
  • 同级技能:../../tests/running-instrumented-tests-via-adb/SKILL.md — am instrument 调用。
  • 同级技能:../../control/injecting-input-and-state/SKILL.md — 捕获前执行手势。
  • 同级技能:../../observability/extracting-logs-with-logcat/SKILL.md — 失败时捕获时配套捕获 logcat。
  • 同级技能:../../transfer/extracting-test-artifacts/SKILL.md — adb pull 和 TestStorageService。
  • 同级技能:../../automation/scripting-adb-for-ci/SKILL.md — 完整的失败时捕获 CI 模式。
  • 跨集合:../../../instrumentation/runner/running-instrumented-tests-with-androidjunit4/SKILL.md — JUnit4 TestWatcher 机制。
  • 跨集合:../../../instrumentation/scenarios/launching-activities-with-activityscenario/SKILL.md — 捕获前,将 Activity 驱动至失败状态。
  • 跨集合:../../../fundamentals/strategies/applying-testing-strategies/SKILL.md — 何时选择失败时捕获,而非每次运行都截屏。

评论

支持 Markdown