Nexus设备默认谷歌相机MediaStore.ACTION_VIDEO_CAPTURE视频访问异常求助
我之前在Nexus设备上用谷歌默认相机做视频拍摄功能时,也踩过这个一模一样的坑!给你分享几个亲测有效的解决办法:
解决Nexus设备谷歌相机拍摄视频后无法访问的问题
问题根源
谷歌相机在处理MediaStore.ACTION_VIDEO_CAPTURE时,返回的Uri权限逻辑和其他第三方相机应用不一样,尤其是在Android 6.0+的动态权限机制下,直接用返回的Uri访问视频会触发权限拒绝的问题。
方案1:用FileProvider指定固定存储路径(最稳妥)
这种方法能彻底绕开相机应用的路径权限问题,直接让视频存在你可控的目录里:
- 在AndroidManifest.xml注册FileProvider
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
- 创建路径配置文件
在res/xml目录下新建file_paths.xml,指定视频存储的位置:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 存在应用私有Movies目录,无需外部存储权限 --> <external-files-path name="captured_videos" path="Movies/" /> </paths>
- 修改拍摄视频的Intent代码
// 创建存储视频的临时文件 File videoStorageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES); File videoFile = new File(videoStorageDir, "new_capture_" + System.currentTimeMillis() + ".mp4"); // 生成FileProvider的Uri Uri outputUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", videoFile); // 构建拍摄Intent Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); // 指定输出路径 takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); // 授予相机应用读写该Uri的临时权限 takeVideoIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); takeVideoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 检查相机应用是否存在 if (takeVideoIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(takeVideoIntent, Globals.REQUEST_CODE_TAKE_VIDEO); }
拍摄完成后,视频会直接存在你指定的应用私有目录,你可以直接读取这个文件,完全不用处理返回Uri的权限问题。
方案2:处理返回Uri的持久化权限(适合不想指定路径的场景)
如果必须用相机默认的存储路径,那得在onActivityResult里申请持久化权限:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == Globals.REQUEST_CODE_TAKE_VIDEO && resultCode == RESULT_OK) { Uri videoUri = data.getData(); if (videoUri != null) { try { // 申请持久化的读取权限 getContentResolver().takePersistableUriPermission( videoUri, Intent.FLAG_GRANT_READ_URI_PERMISSION ); // 之后就可以用ContentResolver正常访问这个Uri了 InputStream is = getContentResolver().openInputStream(videoUri); // 处理视频流... } catch (SecurityException | FileNotFoundException e) { e.printStackTrace(); } } } }
⚠️ 注意:这个方法在部分版本的谷歌相机上可能不稳定,有些情况下相机不会返回支持持久化权限的Uri。
额外提醒
- Android 10及以上版本,访问应用私有目录不需要
WRITE_EXTERNAL_STORAGE权限,用方案1的话可以省去权限申请步骤; - 测试时尽量覆盖不同Android版本的Nexus设备(比如Nexus 5X、6P),不同版本的谷歌相机行为可能略有差异。
内容的提问来源于stack exchange,提问作者Mike Walker
相关产品推荐
相关产品推荐

