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

Android Java实现悬浮覆盖层截取系统屏幕的解决方案

问题原因与解决方案

你的代码只能截取当前应用界面,是因为getWindow().getCurrentFocus()仅能获取到自身App窗口内的View,要实现系统级全屏截图,必须使用Android官方提供的MediaProjection API——这是目前唯一合法获取系统屏幕内容的方式。


第一步:申请屏幕捕获权限

首先需要向用户申请屏幕捕获权限,在你的Activity中添加以下逻辑:

private static final int REQUEST_CODE_SCREEN_CAPTURE = 100;
private MediaProjectionManager mediaProjectionManager;
private MediaProjection mediaProjection;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 初始化MediaProjectionManager
    mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
}

// 发起权限请求(比如在悬浮按钮创建前调用)
private void requestScreenCapturePermission() {
    Intent captureIntent = mediaProjectionManager.createScreenCaptureIntent();
    startActivityForResult(captureIntent, REQUEST_CODE_SCREEN_CAPTURE);
}

// 处理权限回调,保存MediaProjection实例
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == RESULT_OK) {
        mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
    }
}

第二步:替换截图方法为系统级截图

删除你原来的loadBitmapFromView方法,替换为以下系统截图实现:

private Bitmap captureSystemScreen() {
    if (mediaProjection == null) {
        // 权限未授予,可在这里提示用户重新申请
        return null;
    }

    // 获取屏幕尺寸
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    int screenWidth = metrics.widthPixels;
    int screenHeight = metrics.heightPixels;

    // 创建ImageReader用于接收屏幕画面
    ImageReader imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 1);

    // 创建虚拟显示器,将屏幕内容投射到ImageReader
    VirtualDisplay virtualDisplay = mediaProjection.createVirtualDisplay(
            "SystemScreenCapture",
            screenWidth, screenHeight, metrics.densityDpi,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            imageReader.getSurface(),
            null, null);

    // 获取屏幕画面
    Image image = imageReader.acquireLatestImage();
    if (image == null) {
        virtualDisplay.release();
        return null;
    }

    // 将Image对象转换为Bitmap
    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.createBitmap(screenWidth + rowPadding / pixelStride, screenHeight, Bitmap.Config.ARGB_8888);
    bitmap.copyPixelsFromBuffer(buffer);

    // 裁剪掉多余的空白区域(如果存在)
    if (rowPadding > 0) {
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, screenWidth, screenHeight);
    }

    // 释放资源,避免内存泄漏
    image.close();
    virtualDisplay.release();

    return bitmap;
}

第三步:修改触摸事件逻辑

将原来调用loadBitmapFromView的地方替换为新的截图方法:

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_UP) {
        Bitmap screenBitmap = captureSystemScreen();
        if (screenBitmap != null) {
            MediaStore.Images.Media.insertImage(getContentResolver(), screenBitmap, getCurrentTimestampAsFileName(), "");
            // 回收Bitmap,释放内存
            screenBitmap.recycle();
        }
    }
    // 保留你的悬浮按钮移动逻辑
    return true;
}

关键注意事项

  • 权限有效期:MediaProjection权限在设备重启后会失效,需要重新向用户申请。
  • 版本兼容:该API仅支持Android 5.0(API 21)及以上版本,低于此版本无合法系统截图方案。
  • 内存管理:截图生成的Bitmap占用内存较大,使用后务必调用recycle()释放。

内容的提问来源于stack exchange,提问作者Notme112

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:37:33