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

targetSdkVersion 30下如何实现Android全机型兼容的视频图片选择功能

现有实现缺陷说明
  • Intent配置逻辑错误:同时设置ACTION_PICK和ACTION_GET_CONTENT两个冲突的Action,且为ACTION_GET_CONTENT传入了仅对拍照/录屏等输出类Action生效的MediaStore.EXTRA_OUTPUT参数,该参数对选择已有媒体的请求无意义,会导致不同厂商的系统选择器响应逻辑不一致。
  • 权限逻辑冗余且不适配高版本系统:targetSdk≥33后READ_EXTERNAL_STORAGE已完全废弃,且使用系统原生媒体/文件选择器时,无需申请任何存储权限,系统会为选中内容的URI自动授予临时读取权限,权限申请逻辑多余且会在高版本设备上引发授权异常。
  • URI转本地路径的逻辑完全不符合高版本系统规范:Android 10引入分区存储后,应用无法直接访问其他应用/公共目录下的媒体文件路径,你所使用的PathUtils依赖的_data系统数据库列已被官方废弃,返回的路径本身不具备访问权限,是引发崩溃的核心原因。
  • 临时授权丢失:系统选择器返回的URI仅对当前请求的Activity授予临时读取权限,你仅传递转换后的文件路径到下一个Activity,既丢失了URI本身的临时授权,也没有任何机制让下一个Activity获得文件访问权限,三星等厂商的系统权限管控更严格,因此会触发权限错误。
  • 使用已废弃的API:startActivityForResult已在AndroidX Activity 1.2.0、Fragment 1.3.0版本被官方正式废弃,存在兼容性隐患。
官方推荐标准实现方案

所有实现逻辑均有Android官方文档/API规范支撑,全机型适配无权限问题,无需引入任何第三方库。

1. 替换请求逻辑为官方Activity Result API

首先注册媒体选择的结果回调,以选择单视频为例:

// 注册选择视频的结果回调
private val pickVideoLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { selectedUri: Uri? ->
    selectedUri ?: return@registerForActivityResult
    // 直接传递URI到下一个Activity,同时传递读取权限
    val nextIntent = Intent(this, VideoEditActivity::class.java).apply {
        data = selectedUri
        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }
    startActivity(nextIntent)
}

触发媒体选择的逻辑,无需申请任何存储权限:

// 直接拉起系统选择器,不需要申请存储权限
pickVideoLauncher.launch("video/*")

如果需要同时选择图片和视频,可使用官方统一媒体选择器:

// 注册选图/选视频回调
private val pickMediaLauncher = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { selectedUri: Uri? ->
    // 处理逻辑同上
}

// 触发选择,可指定仅图片、仅视频、图片+视频
pickMediaLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo))

2. 修改下一个页面的媒体加载逻辑

不要使用路径加载,直接用URI作为数据源,MediaPlayer原生支持该加载方式:

override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
    Log.d("VIDEOPLAYER", "SURFACE")
    mediaPlayer.setSurface(Surface(surface))
    mediaPlayer.isLooping = true
    // 直接传入上下文和URI设置数据源,不需要文件路径
    mediaPlayer.setDataSource(this, intent.data!!)
    // 后续正常执行prepare、start逻辑即可
}

核心实现依据说明

  1. 系统媒体选择器返回的URI会自动授予临时读取权限,有效期直到应用进程退出,传递给其他组件时仅需添加FLAG_GRANT_READ_URI_PERMISSION即可延续授权,无需申请任何存储权限。
  2. Android 10及以上版本官方明确禁止直接访问公共媒体文件的本地路径,所有访问必须通过URI完成,MediaPlayer原生提供的setDataSource(Context, Uri)重载会自动处理URI的权限校验和资源加载。
  3. Activity Result API是官方指定替代startActivityForResult的标准实现,不存在兼容性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 03:15:02