You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android(API33)下用Kotlin+VideoView读取本地视频的问题

Android 13(API 33)本地视频播放权限与路径问题

我正在开发一款平板端Android应用(基于API 33/Android 13),功能是根据选择播放对应视频。目前能正常播放res/raw目录下的.mp4视频,但由于需要存储约50个单文件25MB左右的视频,且设备运行时无网络,希望将视频存到本地设备中。之前找到的10多年前的解决方案太晦涩,现在有几个关键问题:

当前播放raw目录视频的代码

val workPackage = intent.getParcelableExtra("work_package",WorkModel::class.java)
if(workPackage != null){            
    val resId = resources.getIdentifier(workPackage.Video, "raw", packageName)
    val packageName = "android.resource://" + getPackageName() + "/" + resId

    val uri = Uri.parse(packageName)
    videoView.setVideoURI(uri)

    val mediaController = MediaController(this)
    videoView.setMediaController(mediaController)

    videoView.start()
}

核心疑问

1. 访问Google Files或Google Drive中的视频

如果视频存储在Google Files或Google Drive中,该如何访问?仅仅修改URI即可吗?

2. 权限申请问题

我查了存储相关的官方文档,需要在应用清单中声明权限。我仅需要读取权限,是不是只需要声明uses-permission-sdk-23?

3. 存储路径疑问

Google Files或Google Drive的绝对文件系统路径是什么?有没有更适合存储这类视频的本地位置?


后续测试更新

更新1:尝试使用内部存储Movies目录

我将视频放入内部存储的Movies目录,文件路径为/storage/emulated/0/Movies/crystal.mp4,但尝试以下代码均无法播放:

// 写法1
videoView.setVideoPath("/storage/emulated/0/Movies/crystal.mp4")
// 写法2
val packageName = Environment.getExternalStorageDirectory().path + "/storage/emulated/0/Movies/crystal.mp4"
val uri = Uri.parse(packageName)
// 写法3
val packageName = Environment.getExternalStorageDirectory().path + "/Movies/crystal.mp4"
val uri = Uri.parse(packageName)

更新2:文件存在但无法读取

用file.exists()检查时,路径显示文件存在(进入if分支):

val packageName = "android.resource://" + getPackageName() + "/" + R.raw.crystal
val filePath = "/storage/emulated/0/Movies/crystal.mp4"
val file = File(filePath)
if (file.exists()) {
     // 播放res/raw下的crystal,已知可正常播放
     val uri = Uri.parse(packageName)
     videoView.setVideoURI(uri)
} else {
     // 已知会失败
     videoView.setVideoPath("/crystal.mp4")
}

但用file.canRead()检查时进入了else分支:

val packageName = "android.resource://" + getPackageName() + "/" + R.raw.crystal
val filePath = "/storage/emulated/0/Movies/crystal.mp4"
val file = File(filePath)
if (file.canRead()) {
     // 播放res/raw下的crystal,已知可正常播放
     val uri = Uri.parse(packageName)
     videoView.setVideoURI(uri)
} else {
     // 已知会失败
     videoView.setVideoPath("/crystal.mp4")
}

这说明路径正确但无法读取视频文件,原因是什么?

更新3:确认文件存在但不可读

用嵌套判断进一步测试:

val filePath = "/storage/emulated/0/Movies/crystal.mp4"
val file = File(filePath)
if (file.exists()) {
     if (file.canRead()) {
          val asdf = "android.resource://" + getPackageName() + "/" + R.raw.crystal
          val uri = Uri.parse(asdf) // 存在且可读则播放crystal
          videoView.setVideoURI(uri)
     } else {
          val asdf = "android.resource://" + getPackageName() + "/" + R.raw.testvid
          val uri = Uri.parse(asdf) // 存在但不可读则播放testvid
          videoView.setVideoURI(uri)
     }
} else {
     val asdf = "android.resource://" + getPackageName() + "/" + R.raw.testvid1
     val uri = Uri.parse(asdf) // 不存在则播放testvid1
     videoView.setVideoURI(uri)
}

结果播放了testvid,再次确认路径存在但文件无法读取。

更新4:文件夹可读写,文件不行

将路径修改为仅指向文件夹/storage/emulated/0/Movies/后,file.exists()和file.canRead()均返回true。是不是代码仅检查了文件夹的权限,而非文件本身?

内容的提问来源于stack exchange,提问作者VeronicaV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 09:15:23