You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 15:05:17