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

Android 12/13中MediaStore.ACTION_VIDEO_CAPTURE无法获取视频URI求助

问题分析与解决方案

核心问题在于Android 12/13中,当通过MediaStore.EXTRA_OUTPUT指定视频输出URI时,相机应用不会在返回的Intent中携带视频URI,你的代码中data.getData()会返回null,这是与Android 9及更早版本的行为差异。以下是修复步骤和优化后的代码:


1. 保存输出URI,不依赖返回Intent获取

在启动相机前,将你创建的输出URI保存为成员变量,录制完成后直接使用该URI,而非从返回的Intent中提取。

修改Intent创建代码

// 新增成员变量保存输出URI
private Uri mVideoOutputUri;

private void launchVideoCaptureIntent() {
    mVideoOutputUri = getFileUri("" + System.currentTimeMillis());
    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 60);
    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, mVideoOutputUri);

    if (intent.resolveActivity(getPackageManager()) != null) {
        videoCaptureResultLauncher.launch(intent);
    }
}

修改ActivityResult回调

ActivityResultLauncher<Intent> videoCaptureResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(),
        new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                try {
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        // 直接使用预先保存的输出URI,无需从data中获取
                        videoCaptureResponse(mVideoOutputUri);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    FirebaseCrashlytics.getInstance().recordException(e);
                }
            }
        });

修改videoCaptureResponse方法

private void videoCaptureResponse(Uri selectedVideoUri) throws IOException {
    if (selectedVideoUri == null) {
        // 处理URI为空的异常情况
        return;
    }
    InputStream inputStream = getContentResolver().openInputStream(selectedVideoUri);
    
    ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
    int bufferSize = 1024;
    byte[] buffer = new byte[bufferSize];
    int len = 0;
    while ((len = inputStream.read(buffer)) != -1) {
        byteBuffer.write(buffer, 0, len);
    }
    byte[] arr = byteBuffer.toByteArray();
    int sizeOfInputStram = arr.length;

    stringEncoded = android.util.Base64.encodeToString(arr, android.util.Base64.DEFAULT);
    
    MediaMetadataRetriever mMMR = new MediaMetadataRetriever();
    mMMR.setDataSource(WitnessCRPCActivity.this, selectedVideoUri);
    Bitmap bmp = mMMR.getFrameAtTime();
    filecamera.setImageBitmap(bmp);
}

2. 确保getFileUri()实现符合Android 10+存储规范

Android 10及以上禁止直接使用file:// URI,必须通过FileProvider(私有目录)或MediaStore(公共媒体库)生成URI。

方案一:使用FileProvider(推荐,无需存储权限)

1. 注册FileProvider到AndroidManifest.xml

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.your.package.name.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

2. 创建res/xml/file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="movies" path="Movies" />
</paths>

3. 实现getFileUri()

private Uri getFileUri(String fileName) {
    File videoDir = new File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "YourAppVideos");
    if (!videoDir.exists()) videoDir.mkdirs();
    File videoFile = new File(videoDir, fileName + ".mp4");
    return FileProvider.getUriForFile(this, "com.your.package.name.fileprovider", videoFile);
}

方案二:使用MediaStore(保存到公共媒体库)

private Uri getFileUri(String fileName) {
    ContentValues values = new ContentValues();
    values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName + ".mp4");
    values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
    values.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES + "/YourAppName");
    
    return getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
}

3. 动态申请相机权限

Android 6及以上需要动态申请CAMERA权限,否则无法启动相机录制:

ActivityResultLauncher<String> requestCameraPermissionLauncher = registerForActivityResult(
    new ActivityResultContracts.RequestPermission(),
    isGranted -> {
        if (isGranted) {
            launchVideoCaptureIntent();
        } else {
            // 提示用户开启相机权限
        }
    });

// 触发权限申请
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA);

内容的提问来源于stack exchange,提问作者Rameswar Tarai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 18:23:26