Android 13 媒体权限适配指南
The following article is from 字节数组 Author 业志陈
Android 10。分区存储、限制访问不可重置的硬件标识符、限制对剪贴板数据的访问权限 Android 11。强制执行分区存储、单次授权、自动重置权限、软件包可见性。 Android 12。授予大致位置信息权限、剪贴板访问通知、更安全的组件导出。 Android 13。细化的媒体权限、内置图片选择器、隐藏剪贴板中的敏感内容、屏蔽不匹配的 Intent、针对 Wifi 设备的新运行时权限、广告 ID 权限。
以上两个问题,依靠在 Android 13 中新增的两个隐私安全项:细化的媒体权限 和 内置图片选择器,也终于能够得到解决了,后面来一一进行讲解。
媒体类型 | 请求权限 |
如果应用还未适配 Android 13,也即 targetSdkVersion 小于 33。 此时不管系统版本是多少,依然还是通过 READ_EXTERNAL_STORAGE 权限来访问媒体资源。 如果应用已适配 Android 13,也即 targetSdkVersion 大于等于 33。 如果系统版本小于 33,此时依然要通过 READ_EXTERNAL_STORAGE 才能访问媒体资源。 如果系统版本大于等于 33,此时必须通过这三个细分权限才能访问媒体资源,READ_EXTERNAL_STORAGE 权限已失效。
几个月前我发布了一个开源库, 一个用 Jetpack Compose 实现的 Android 图片选择框架:Matisse。
https://github.com/leavesCZY/Matisse
完全用 Kotlin 实现,拒绝 Java。 UI 层完全用 Jetpack Compose 实现,拒绝原生 View 体系。 支持精细自定义主题,默认提供了 日间 和 夜间 两种主题。 支持精准筛选图片类型,只显示想要的图片类型。 支持在图片列表页开启拍照入口,同时支持 FileProvider 和 MediaStore 两种拍照策略。 支持详细获取图片信息,一共包含 uri、displayName、mimeType、width、height、orientation、size、path、bucketId、bucketDisplayName 等十个属性值。 适配到 Android 12。
private fun requestReadImagesPermission() {
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
applicationInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU
) {
Manifest.permission.READ_MEDIA_IMAGES
} else {
Manifest.permission.READ_EXTERNAL_STORAGE
}
if (PermissionUtils.checkSelfPermission(context = this, permission = permission)) {
//已获得必要权限,可以去加载系统相册图片了
} else {
//去申请必要权限
}
}
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
搭载 Android 11(API 级别 30)或更高版本。 通过 Google 系统更新接收对模块化系统组件的更改。
//compileSdkVersion 需要至少为 33 才可以调用此方法
fun isPhotoPickerAvailable(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
true
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getExtensionVersion(Build.VERSION_CODES.R) >= 2
} else {
false
}
}
PickVisualMedia。用于选择单张图片或单个视频。 PickMultipleVisualMedia。用于选择多张图片或多个视频。
private val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri != null) {
//TODO
}
}
//选择图片或视频
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo))
//仅选择图片
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
//仅选择视频
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.VideoOnly))
//仅选择 Gif 图片
val mimeType = "image/gif"
pickMedia.launch(
PickVisualMediaRequest(
ActivityResultContracts.PickVisualMedia.SingleMimeType(
mimeType
)
)
)
private val pickMultipleMedia = registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(5)) { uris ->
if (uris.isNotEmpty()) {
//TODO
}
}
需要注意,以上代码需要添加 1.6.0 或更高版本的 androidx.activity 库后才可以使用。此外,从 PickVisualMedia 和 PickMultipleVisualMedia 的源码可以看到,Android 13 内置的图片选择器对应的是 MediaStore.ACTION_PICK_IMAGES 这个新增的 Intent,而如果当前设备不支持媒体选择器功能的话,就会改为通过调用 Intent.ACTION_OPEN_DOCUMENT 来选择媒体资源,这种情况下 PickMultipleVisualMedia 设定的数量上限自然也就失效了。
在 Android 13 之前依然还是通过应用内置的图片选择器来实现业务功能。 在 Android 13 开始之后的版本仅使用系统内置的图片选择器,完全弃用 READ_EXTERNAL_STORAGE 权限。
最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!
推荐阅读:
扫一扫 关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!