Android:从Raw Assets存本地的视频无法通过隐式Intent播放
解决FileProvider分享视频无法被第三方应用播放的问题
嘿,我帮你排查了下代码里的几个关键问题,这应该就是VLC和谷歌相册打不开视频的原因:
1. 最关键的遗漏:给Intent添加读取权限
FileProvider生成的Uri是受权限保护的,你必须显式授予目标应用临时读取权限,不然第三方应用根本读不到文件内容。修改Intent的创建代码:
Uri uri = FileProvider.getUriForFile(getApplicationContext(), getPackageName(), videoFile); Intent in = new Intent(Intent.ACTION_VIEW); in.setDataAndType(uri, "video/*"); // 必须加这个!授予读取Uri的临时权限 in.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 可选:如果是Android 10+,加上这个避免启动模式的问题 // in.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(in);
2. 文件复制逻辑有坑:is.available()不可靠
你用is.available()一次性读取整个文件的方式,只适合极小的文件。对于视频这类大文件,available()只能返回当前瞬间能读到的字节数,会导致复制不完整(视频损坏)。改成循环读写的正确方式:
if (!videoFile.exists()) { try (InputStream is = getResources().openRawResource(R.raw.talking); OutputStream os = new FileOutputStream(videoFile)) { byte[] buffer = new byte[4096]; // 用4KB缓冲区循环读写,效率更高 int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } } catch (IOException e) { Log.w("ExternalStorage", "Error writing " + videoFile, e); Toast.makeText(this, "Failed to copy talking.mp4", Toast.LENGTH_LONG).show(); return; } }
这里用了try-with-resources语法,不用手动关闭流,更安全不容易出错。
3. 存储目录的可靠性问题
getExternalFilesDirs(null)[1]是外接SD卡的目录,但不是所有设备都有SD卡,直接取索引1会导致空指针或者目录不存在。先检查目录是否可用:
File[] externalDirs = getExternalFilesDirs(null); File targetDir = null; // 优先用主外部存储(索引0),有可用SD卡再用 for (File dir : externalDirs) { if (dir != null && Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(dir))) { targetDir = dir; break; } } if (targetDir == null) { Toast.makeText(this, "No available external storage", Toast.LENGTH_LONG).show(); return; } File videoFile = new File(targetDir, "talking.mp4");
你的FileProvider配置里external-files-path已经覆盖了这个目录,所以只要目录有效,映射就没问题。
4. 最后验证点
- 先确认复制后的
videoFile大小和raw目录里的原文件一致,排除复制不全的问题 - 先用系统自带播放器测试,能正常播放再试第三方应用
内容的提问来源于stack exchange,提问作者CybeX
相关产品推荐
相关产品推荐

