MediaStore.ACTION_VIDEO_CAPTURE在诺基亚G10无法写入完整视频字节如何解决
问题修复方案
你遇到的是诺基亚G10预装相机应用的兼容性问题,核心原因有两点:
- 你给Intent加的
FLAG_GRANT_WRITE_URI_PERMISSION仅对Intent的data字段生效,对EXTRA_OUTPUT携带的Uri不生效,该设备的相机应用没有拿到自定义路径的完整写入权限,导致文件写入到一半被中断 - 该设备相机应用写入自定义路径的视频时,没有完整写入视频尾部的索引元数据(moov原子),导致播放器只能读取到前面的帧
修复步骤
1. 修正Uri权限授予逻辑
不要依赖Intent的flag自动授权,手动给所有匹配拍照Intent的相机应用授予Uri的读写权限
2. 修正FileProvider的SDK版本判断
原代码判断SDK_INT > N_MR1(API25)才用FileProvider,Android 7.0(API24)就已经禁止Uri.fromFile的跨进程传递,需要调整判断条件
3. 添加录制完成后的兜底复制逻辑
如果自定义路径的文件损坏,直接将相机默认输出的视频复制到你的自定义目录,完全规避相机写入自定义路径的兼容性问题
4. 优化FileProvider配置
避免暴露整个存储根目录,减少权限风险
修正后的代码
调用录制Intent的代码
Intent(MediaStore.ACTION_VIDEO_CAPTURE).also { takeVideoIntent -> val resolvedActivities = activity!!.packageManager.queryIntentActivities(takeVideoIntent, 0) if (resolvedActivities.isNotEmpty()) { val videoUri = getFileUri(activity!!, filePath) // 手动给所有匹配的相机应用授予Uri读写权限 resolvedActivities.forEach { resolveInfo -> val packageName = resolveInfo.activityInfo.packageName activity!!.grantUriPermission( packageName, videoUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION ) } takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri) takeVideoIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0) takeVideoIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 60) startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE) } }
修正后的getFileUri方法
fun getFileUri(activity: Activity, filePath: File): Uri { // Android 7.0及以上统一使用FileProvider return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { FileProvider.getUriForFile( activity, BuildConfig.APPLICATION_ID + ".provider", filePath ) } else { Uri.fromFile(filePath) } }
优化后的FileProvider paths配置
替换原有paths配置,把your_custom_folder改成你实际的存储文件夹名即可
<?xml version="1.0" encoding="utf-8"?> <paths> <!-- 仅暴露你需要用到的自定义目录,不要暴露整个根目录 --> <external-files-path name="app_video_folder" path="your_custom_folder/" /> </paths>
onActivityResult兜底处理逻辑
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == Activity.RESULT_OK) { val targetFile = filePath // 你的自定义路径文件 // 检查文件是否正常,10秒低清视频至少大于2MB,可根据你的画质调整阈值 if (targetFile.length() < 2 * 1024 * 1024) { // 文件损坏,从相机默认输出的Uri复制到自定义路径 data?.data?.let { defaultUri -> contentResolver.openInputStream(defaultUri)?.use { inputStream -> FileOutputStream(targetFile).use { outputStream -> inputStream.copyTo(outputStream) } } // 复制完成后可删除系统默认存储的视频 contentResolver.delete(defaultUri, null, null) } } // 收回之前授予的Uri权限 val videoUri = getFileUri(this, filePath) revokeUriPermission(videoUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION) } }
内容的提问来源于stack exchange,提问作者Rizwan Rasheed
相关产品推荐
相关产品推荐

