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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 17:10:20