Android使用MediaProjectionManager获取游戏画面和投屏
MediaProjectionManager 是 Android 系统中实现屏幕录制和截屏功能的管理器,允许应用请求用户授权并获取屏幕投影,进而实现屏幕内容的录制或截图 。
使用步骤
- 获取 MediaProjectionManager 实例:
通过 getSystemService(Context.MEDIA_PROJECTION_SERVICE) 获取 。
- 请求权限:
使用 createScreenCaptureIntent() 创建用于请求屏幕捕获权限的 Intent,并通过 startActivityForResult() 启动该 Intent 。此时系统会显示请求授权的弹窗。
- 处理授权结果:
在 onActivityResult() 中,判断弹窗成功授权后启动服务。若结果码为 RESULT_OK,则通过 getMediaProjection(resultCode, data) 获取 MediaProjection 对象 。
- 创建 VirtualDisplay:
使用 MediaProjection.createVirtualDisplay() 创建虚拟显示,传入屏幕宽度、高度、密度等参数,并指定一个 Surface(如 ImageReader 或 SurfaceView 的 Surface)以捕获屏幕内容 。
createVirtualDisplay 说明
参数详解
参数名 | 含义说明 |
| 虚拟显示的名称,不能为空字符串。 |
| 虚拟屏幕的宽度(像素),必须 > 0。 |
| 虚拟屏幕的高度(像素),必须 > 0。 |
| 屏幕密度(dpi),建议与真实屏幕一致,可通过 |
| 控制虚拟显示行为的标志位,如 |
| 渲染目标,通常是 |
| 监听虚拟显示状态变化的回调,可为 |
| 指定回调线程的 |
常用 Flags
Flag 名称 | 含义说明 |
| 公共显示,允许其他应用在此显示上打开窗口。默认是私有的。 |
| 设置为演示显示,常用于双屏展示场景。 |
| 安全显示,防止内容被截屏/录制(需系统权限)。 |
| 仅显示自己的内容,不镜像其他屏幕内容。 |
| 自动镜像主屏幕内容(常用于录屏)。需要 |
示例代码:
val mediaProjectionManager = getSystemService(MediaProjectionManager::class.java)
val startMediaProjection = registerForActivityResult(StartActivityForResult()) { result ->if (result.resultCode == RESULT_OK) {val mediaProjection = mediaProjectionManager.getMediaProjection(result.resultCode, result.data!!)val displayMetrics = resources.displayMetricsval surface = mediaRecorder.surface // 也可以是 ImageReader.getSurface()val virtualDisplay = mediaProjection.createVirtualDisplay("ScreenCapture",displayMetrics.widthPixels,displayMetrics.heightPixels,displayMetrics.densityDpi,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,surface,null,null)}
}
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent())
如需进一步处理画面(如截图或编码),可将 Surface 替换为 ImageReader 或 MediaCodec 的输入 Surface,灵活适配不同使用场景。
注意事项
Android 5.0 及以上版本支持
MediaProjection
功能 。需处理用户拒绝授权的情况,确保良好的用户体验 。
在 Android 10 及以上版本中,注意存储权限等适配问题 。
权限要求:必须在每次使用前通过
createScreenCaptureIntent()
获取用户授权。一次性使用:Android 14+ 中,
MediaProjection
令牌只能用于一次createVirtualDisplay()
调用。资源释放:使用完后必须调用
virtualDisplay.release()
和mediaProjection.stop()
,避免内存泄漏。