Android应用内实现系统截图而非应用截图的方法求助
Android应用实现系统级屏幕截图方案
你之前的代码只能截取当前应用自身的界面,因为getWindow().getDecorView().getRootView()获取的是当前应用窗口的根视图,无法访问系统全局的屏幕内容,所以当应用最小化后,这种方法完全失效。要实现系统级截图(包括其他应用界面、桌面等),必须使用Android官方提供的MediaProjection API,这是目前唯一合法且稳定的实现方式。
实现步骤及代码示例
1. 配置权限清单
在AndroidManifest.xml中添加必要的文件访问权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 13及以上需要添加以下权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
2. 发起系统截图授权请求
系统级截图需要用户手动授权,通过MediaProjectionManager启动授权界面:
private static final int REQUEST_CODE_SCREEN_CAPTURE = 100; private MediaProjectionManager mediaProjectionManager; // 触发授权流程 private void requestScreenCapturePermission() { mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); Intent captureIntent = mediaProjectionManager.createScreenCaptureIntent(); startActivityForResult(captureIntent, REQUEST_CODE_SCREEN_CAPTURE); } // 处理授权结果 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == RESULT_OK) { // 授权成功,开始执行截图逻辑 startScreenCapture(resultCode, data); } }
3. 核心截图逻辑实现
通过MediaProjection创建虚拟显示器,将屏幕内容投射到ImageReader,再将帧数据转换为Bitmap并保存:
private MediaProjection mediaProjection; private VirtualDisplay virtualDisplay; private ImageReader imageReader; private void startScreenCapture(int resultCode, Intent data) { mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data); if (mediaProjection == null) return; // 获取当前屏幕的尺寸和密度 DisplayMetrics metrics = getResources().getDisplayMetrics(); int screenWidth = metrics.widthPixels; int screenHeight = metrics.heightPixels; int screenDensity = metrics.densityDpi; // 创建ImageReader用于捕获屏幕帧 imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 1); // 创建虚拟显示器,将屏幕内容输出到ImageReader的Surface virtualDisplay = mediaProjection.createVirtualDisplay( "SystemScreenCapture", screenWidth, screenHeight, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, imageReader.getSurface(), null, null ); // 监听ImageReader的帧数据,完成截图 imageReader.setOnImageAvailableListener(reader -> { Image image = null; try { image = reader.acquireLatestImage(); if (image == null) return; Image.Plane[] planes = image.getPlanes(); ByteBuffer buffer = planes[0].getBuffer(); int pixelStride = planes[0].getPixelStride(); int rowStride = planes[0].getRowStride(); int rowPadding = rowStride - pixelStride * screenWidth; // 转换为Bitmap并裁剪多余的填充区域 Bitmap bitmap = Bitmap.createBitmap( screenWidth + rowPadding / pixelStride, screenHeight, Bitmap.Config.ARGB_8888 ); bitmap.copyPixelsFromBuffer(buffer); Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, 0, 0, screenWidth, screenHeight); bitmap.recycle(); // 保存截图到本地文件 saveScreenshotToFile(croppedBitmap); croppedBitmap.recycle(); } catch (Exception e) { e.printStackTrace(); } finally { // 及时释放资源,避免内存泄漏 if (image != null) image.close(); if (virtualDisplay != null) virtualDisplay.release(); if (mediaProjection != null) mediaProjection.stop(); imageReader.close(); } }, null); } // 保存Bitmap到外部存储的方法 private void saveScreenshotToFile(Bitmap bitmap) { File saveDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); if (!saveDir.exists()) saveDir.mkdirs(); File screenshotFile = new File(saveDir, "screenshot_" + System.currentTimeMillis() + ".png"); try (FileOutputStream fos = new FileOutputStream(screenshotFile)) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); // 通知系统图库更新,让截图立即显示在相册中 MediaScannerConnection.scanFile(this, new String[]{screenshotFile.getAbsolutePath()}, null, null); } catch (IOException e) { e.printStackTrace(); } }
关键注意事项
- 授权限制:截图授权必须由用户主动触发(比如点击按钮),不能在后台自动请求,否则会被系统拒绝。
- 资源释放:截图完成后必须释放
MediaProjection、VirtualDisplay和ImageReader,否则会造成内存泄漏。 - 版本兼容:MediaProjection API从Android 5.0(API 21)开始支持,Android 10及以上是唯一合法的系统截图方式,旧版本的私有API已被禁用。
- 后台截图:如果需要在应用后台完成截图,需要确保
MediaProjection实例保持活跃,但系统可能会在应用后台时限制虚拟显示器的创建,需测试不同设备的表现。
内容的提问来源于stack exchange,提问作者Bob Dole
相关产品推荐
相关产品推荐

