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
相关产品推荐
相关产品推荐

