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
相关产品推荐
相关产品推荐

