如何通过Kotlin代码将Android Studio模拟器截图传输至主机?
在JUnit测试中实时将模拟器内截图传输到主机文件系统的实现方案
核心思路
既然模拟器会在每次测试后重启,那就不要等到测试结束后再传输文件,而是在每个测试用例生成截图后,立即通过adb pull命令将模拟器内的截图文件同步到主机文件系统。这样每个测试的截图都会被实时保存,不会因为模拟器重启丢失。
具体实现步骤
- 生成截图并保存到模拟器的可读写目录(比如外部存储的Pictures目录下)
- 在测试代码中调用
adb pull命令,将模拟器内的截图文件拉取到主机的指定路径(比如代码仓库下的截图目录) - 验证命令执行结果,确保传输成功
Kotlin代码示例
1. 保存Bitmap到模拟器
private fun saveBitmapToEmulator(bitmap: Bitmap, fileName: String): String { // 选择模拟器外部存储的可访问目录,确保测试有写入权限 val screenshotDir = File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test_screenshots" ) if (!screenshotDir.exists()) screenshotDir.mkdirs() val screenshotFile = File(screenshotDir, fileName) FileOutputStream(screenshotFile).use { out -> bitmap.compress(Bitmap.CompressFormat.PNG, 100, out) } return screenshotFile.absolutePath }
2. 执行adb拉取文件到主机
private fun pullScreenshotToHost(emulatorFilePath: String, hostFilePath: String) { // 构造adb pull命令 val adbCommand = listOf( "adb", "pull", emulatorFilePath, hostFilePath ) // 执行命令并处理结果 val process = ProcessBuilder(adbCommand) .redirectErrorStream(true) .start() process.waitFor() val exitCode = process.exitValue() if (exitCode != 0) { val errorMsg = process.inputStream.bufferedReader().readText() throw RuntimeException("拉取截图失败: $errorMsg") } }
3. 在测试用例中调用
@RunWith(AndroidJUnit4::class) class ScreenshotTest { @get:Rule val activityRule = ActivityScenarioRule(MainActivity::class.java) // 授予存储读写权限 @get:Rule val grantPermissionRule = GrantPermissionRule.grant( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE ) @Test fun testHomeScreenCapture() { // 获取根视图并生成Bitmap activityRule.scenario.onActivity { activity -> val rootView = activity.window.decorView.rootView rootView.isDrawingCacheEnabled = true val bitmap = Bitmap.createBitmap(rootView.drawingCache) rootView.isDrawingCacheEnabled = false // 生成唯一文件名,避免重复 val fileName = "test_home_screen_${System.currentTimeMillis()}.png" val emulatorPath = saveBitmapToEmulator(bitmap, fileName) // 主机目标路径:代码仓库根目录下的screenshots文件夹 val hostRootPath = System.getProperty("user.dir") ?: "." val hostPath = "$hostRootPath/screenshots/$fileName" // 实时拉取到主机 pullScreenshotToHost(emulatorPath, hostPath) } } }
关键注意事项
- adb环境配置:确保
adb命令在系统PATH中,或者在代码里指定adb的绝对路径(比如/Users/xxx/Library/Android/sdk/platform-tools/adb) - 权限问题:必须通过
GrantPermissionRule授予测试应用存储读写权限,否则无法写入模拟器外部存储 - 测试环境:该方案仅适用于Instrumented Test(运行在设备/模拟器上的测试),不适用于本地单元测试
- 文件名唯一性:建议用测试方法名+时间戳命名截图,避免不同测试的截图覆盖
- 目录提前创建:主机的目标目录(比如
screenshots)需要提前创建,或者在代码里判断并创建
内容的提问来源于stack exchange,提问作者Deep
相关产品推荐
相关产品推荐

