Android 14/SDK34下Media Projection Service反复请求权限求助
Android 14(SDK34)下MediaProjection权限重复触发问题解决思路
问题背景
应用需要每5秒录制一次屏幕并生成MP4文件,在SDK33及以下版本中,复用授权后的Capture Intent即可实现一次权限请求完成多轮录制;但升级到SDK34后,即便复用同一Intent,每次录制前都会触发MediaProjection权限弹窗。
原因分析
Android 14对MediaProjection权限机制做了核心变更:当调用MediaProjection.stop()释放实例后,对应的授权会话直接失效。再次使用同一resultCode和Intent创建MediaProjection时,系统会强制重新发起权限请求。而SDK33及以下版本允许复用已授权的Intent重建实例,无需再次授权。
可行解决方案
方案一:复用MediaProjection实例(全版本兼容)
核心逻辑是保持MediaProjection实例始终活跃,仅在录制轮次间启停MediaRecorder,不释放MediaProjection,以此维持权限会话有效性。
具体实现步骤:
- 首次授权成功后,创建并保存MediaProjection实例,不要在单轮录制结束时调用
mediaProjection.stop()。 - 每轮新录制直接复用已保存的MediaProjection实例创建MediaRecorder并启动录制。
- 仅当应用彻底不再需要录屏功能时,才调用
mediaProjection.stop()释放资源。
方案二:请求持久化屏幕捕获权限(Android 14+专属)
使用Android 14新增的MediaProjectionManager.createPersistentScreenCaptureIntent()请求持久化权限,用户授权后,即便MediaProjection被释放,后续重建实例也无需再次弹窗请求权限。
具体实现步骤:
- 针对SDK34及以上版本,替换原有的
createScreenCaptureIntent()为createPersistentScreenCaptureIntent()。 - 授权成功后保存
resultCode和Intent,后续创建MediaProjection时直接复用即可。 - 需在AndroidManifest中添加权限声明:
<uses-permission android:name="android.permission.PERSISTENT_SCREEN_CAPTURE" />(仅SDK34+生效)。
代码修改示例
结合现有代码,以下是兼容两种方案的修改版本:
// 新增成员变量保存MediaProjection实例 private MediaProjection mediaProjection; // RUN SERVICE AND START RECORDING public void runService() { if (!permissionGranted) { MediaProjectionManager manager = (MediaProjectionManager) mainActivity .getSystemService(Context.MEDIA_PROJECTION_SERVICE); Intent intent = null; if (manager != null) { // 根据SDK版本选择对应的权限请求Intent if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { intent = manager.createPersistentScreenCaptureIntent(); } else { intent = manager.createScreenCaptureIntent(); } mainActivity.startActivityForResult(intent, CAPTURE_CODE); permissionGranted = true; } else if (reactContext != null) { onPermissionResult(reactContext, "capture-intent-error"); } } else { // 优先复用已存在的MediaProjection实例 if (mediaProjection != null) { startWithExistingProjection(); } else { start(CAPTURE_INTENT, INIT_RESULT_CODE); } } } // ON MEDIAPROJECTION ACTIVITY RESULT public void onActivityResult(int requestCode, int resultCode, Intent intent) { INIT_RESULT_CODE = resultCode; CAPTURE_INTENT = intent; if (resultCode == -1 && reactContext != null) { onPermissionResult(reactContext, "granted"); // 创建并保存MediaProjection实例 MediaProjectionManager manager = (MediaProjectionManager) mainActivity .getSystemService(Context.MEDIA_PROJECTION_SERVICE); if (manager != null) { mediaProjection = manager.getMediaProjection(resultCode, intent); } startWithExistingProjection(); } else if (resultCode == 0 && reactContext != null) { onPermissionResult(reactContext, "denied"); } } // 复用已有MediaProjection启动录制的方法 private void startWithExistingProjection() { // 此处实现你的录制逻辑:使用已保存的mediaProjection创建MediaRecorder // 注意:单轮录制结束时仅停止MediaRecorder,不要调用mediaProjection.stop() }
注意事项
- 方案一需注意内存占用,确保在应用退出或不再需要录屏时及时释放MediaProjection。
- 使用方案二时,要遵守Android 14对持久化录屏权限的限制,避免滥用导致用户反感。
- 无论哪种方案,都需符合Android后台录屏的系统规则,避免应用被后台限制或杀死。
内容的提问来源于stack exchange,提问作者technoshaman
相关产品推荐
相关产品推荐

