Android编程:如何检测Overlay并捕获含其与Toast的全屏截图?
实现全屏截图(含Overlay/Toast)+ Overlay监听方案
一、全屏截图核心实现:MediaProjection API
你之前的代码只能捕获当前Activity视图,原因是window.decorView仅对应自身App界面。要捕获包含Overlay、Toast在内的整个屏幕,必须使用Android官方提供的MediaProjection API——无需root权限,能覆盖所有屏幕显示元素。
1. 申请MediaProjection权限
首先启动系统权限申请界面:
private val REQUEST_CODE_SCREEN_CAPTURE = 1001 fun requestScreenCapturePermission() { val mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager val intent = mediaProjectionManager.createScreenCaptureIntent() startActivityForResult(intent, REQUEST_CODE_SCREEN_CAPTURE) } // 处理权限申请结果 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == RESULT_OK) { val mediaProjection = (getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager) .getMediaProjection(resultCode, data!!) startScreenCapture(mediaProjection) } }
2. 执行全屏截图
通过ImageReader捕获屏幕帧并转换为Bitmap保存:
private fun startScreenCapture(mediaProjection: MediaProjection) { val displayMetrics = resources.displayMetrics val screenWidth = displayMetrics.widthPixels val screenHeight = displayMetrics.heightPixels // 创建ImageReader,指定屏幕分辨率和像素格式 val imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 1) // 创建VirtualDisplay,将屏幕内容投射到ImageReader的Surface val virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", screenWidth, screenHeight, displayMetrics.densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, imageReader.surface, null, null ) // 监听新帧生成 imageReader.setOnImageAvailableListener({ reader -> val image = reader.acquireLatestImage() ?: return@setOnImageAvailableListener val planes = image.planes val buffer = planes[0].buffer val pixelStride = planes[0].pixelStride val rowStride = planes[0].rowStride val rowPadding = rowStride - pixelStride * screenWidth // 转换为Bitmap并裁剪多余padding val bitmap = Bitmap.createBitmap( screenWidth + rowPadding / pixelStride, screenHeight, Bitmap.Config.ARGB_8888 ) bitmap.copyPixelsFromBuffer(buffer) val croppedBitmap = Bitmap.createBitmap(bitmap, 0, 0, screenWidth, screenHeight) bitmap.recycle() // 保存截图文件 saveBitmapToFile(croppedBitmap) // 释放资源 image.close() imageReader.close() virtualDisplay.release() mediaProjection.stop() }, Handler(Looper.getMainLooper())) } private fun saveBitmapToFile(bitmap: Bitmap) { val mPath = "${cacheDir.absolutePath}/temp_${System.currentTimeMillis()}.png" val imageFile = File(mPath) FileOutputStream(imageFile).use { outputStream -> bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream) } bitmap.recycle() }
二、监听Overlay窗口显示
要检测其他应用的Overlay窗口,需使用AccessibilityService,它能监听系统所有窗口的状态变化。
1. 配置AccessibilityService
在res/xml目录下创建accessibility_service_config.xml:
<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:description="@string/accessibility_service_desc"/>
在AndroidManifest.xml中注册服务:
<service android:name=".OverlayMonitorService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService"/> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config"/> </service>
2. 实现Overlay监听逻辑
创建OverlayMonitorService类:
class OverlayMonitorService : AccessibilityService() { override fun onAccessibilityEvent(event: AccessibilityEvent) { if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { val windowInfo = event.source?.windowInfo ?: return // 判断是否为Overlay类型窗口 if (windowInfo.type == AccessibilityWindowInfo.TYPE_APPLICATION_OVERLAY || windowInfo.type == AccessibilityWindowInfo.TYPE_SYSTEM_OVERLAY) { // 检测到Overlay显示,触发截图逻辑 Handler(Looper.getMainLooper()).post { // 调用之前的截图方法,若权限已过期需重新申请 // requestScreenCapturePermission() } } } } override fun onInterrupt() {} }
关键注意事项
- MediaProjection权限需用户手动授权,且设备重启后权限失效,需重新申请。
- AccessibilityService需要用户在系统设置中手动开启(路径:设置→无障碍→你的应用服务)。
- 建议添加截图防抖逻辑,避免因窗口频繁切换触发过多截图操作。
内容的提问来源于stack exchange,提问作者Krunal Indrodiya
相关产品推荐
相关产品推荐

