Android 13模拟器使用ACTION_PICK选视频后黑屏问题排查
Android 13模拟器选择视频后编辑界面黑屏问题排查与解决
问题根源
- Android 13(API 33+)对媒体文件访问权限管控更严格,直接解析
content://类型Uri到绝对路径并通过FileInputStream访问,会因权限不足导致文件读取失败,最终视频无法加载显示黑屏。 - 第三方相册(如谷歌相册)返回的
content://Uri并非直接指向本地文件路径,parsePath解析出的路径可能无效或无读取权限。 - 传递文件路径的方式忽略了Uri的临时权限,即便添加
FLAG_GRANT_READ_URI_PERMISSION,目标Activity也无法通过路径获取对应权限。
解决方案
1. 直接传递Uri而非解析后的文件路径
修改Fragment中跳转Activity的代码,直接传递选中的Uri:
R.id.imageViewVideo -> { val intent = Intent(Intent.ACTION_PICK).apply { type = "video/*" } resultLauncher.launch(intent) } private val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val videoUri: Uri? = result.data?.data ?: return@registerForActivityResult val intent = Intent(requireContext(), SelectVideoActivity::class.java).apply { data = videoUri addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } startActivity(intent) } }
2. 在SelectVideoActivity中通过ContentResolver读取Uri内容
替换FileInputStream为ContentResolver.openInputStream(),规避权限问题:
// 初始化inputFile逻辑保留 private lateinit var inputFile: File inputFile = File(getExternalFilesDir("app-mnme")!!.absolutePath + "/${System.currentTimeMillis()}.mp4") // 接收Uri并执行复制 val videoUri = intent.data ?: return copyFile(videoUri, inputFile) // 修改copyFile函数,接收Uri参数 @Throws(IOException::class) fun copyFile(sourceUri: Uri, destFile: File) { try { if (!destFile.parentFile!!.exists()) destFile.parentFile!!.mkdirs() if (!destFile.exists()) { destFile.createNewFile() } contentResolver.openInputStream(sourceUri)?.use { inputStream -> FileOutputStream(destFile).use { outputStream -> inputStream.copyTo(outputStream) } } ?: throw IOException("无法打开视频输入流") } catch (e: Exception) { Log.i("error", "selectvideo ${e.message}") } finally { initViews() setListener() } }
3. 移除不可靠的路径解析逻辑
删除parsePath相关代码,Android 13及以上版本中,解析content:// Uri到绝对路径的方式已不再可靠,且易引发权限问题。
4. 权限适配(可选)
若应用有其他媒体操作需求,在Android 13及以上版本需正确申请READ_MEDIA_VIDEO权限:
private fun requestVideoPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { requestPermissions(arrayOf(Manifest.permission.READ_MEDIA_VIDEO), 1001) } }
验证要点
- 查看
copyFile函数的异常日志,确认是否仍存在读取失败情况。 - 确保
inputFile存储在应用私有外部目录,避免额外存储权限问题。
内容的提问来源于stack exchange,提问作者sejn
相关产品推荐
相关产品推荐

