Android-适配记录API28~33:读写权限变更记录
背景
因为Android应用市场要求是最低要求API 30以上,我准备就直接从API 28升到API 33了,其中遇到了一些读写存储空间的问题,这里做一些记录总结~
相关权限:
permission.READ_EXTERNAL_STORAGE
permission.WRITE_EXTERNAL_STORAGE
permission.MANAGE_EXTERNAL_STORAGE
permission.READ_MEDIA_VIDEO
permission.READ_MEDIA_IMAGES
permission.READ_MEDIA_AUDIO
相关知识点
低版本的,我这里就不说明了
- Android 10(API 级别 29)开始,
android.permission.WRITE_EXTERNAL_STORAGE
权限的行为发生了变化,这个权限默认情况下被视为无效,可以通过permission.MANAGE_EXTERNAL_STORAGE
获取全部文件的权限,但是只有系统应用程序或具有特殊要求的应用程序才能申请此权限,Environment.isExternalStorageManager()
判断自己是否获取了全部的权限。Environment.getExternalStorageDirectory()
在没有权限时,是无法访问的。 android:requestLegacyExternalStorage="true"
是一个用于在 Android 10(API 级别 29)及以上版本中启用传统外部存储权限模式的应用程序清单属性,Android 11(API 级别 30)中将不再生效。- Android 11(API 级别 30) 后,默认获取权限可以通过
/storage/emulated/0/Android/data/包名/file
,不需要特殊的权限,因为这个目录是应用程序的私有目录,删除app后会同时删除。 - Android 11(API 级别 30) 中,读取媒体文件的权限受到了更严格的限制。即使你声明了
READ_EXTERNAL_STORAGE
权限,你的应用程序也只能访问自己的媒体文件或存储在媒体库中的公共文件。如果你需要访问其他应用程序的媒体文件,你需要使用 Storage Access Framework 或 MediaStore API 来进行访问。 - 要读取媒体文件(如图片、音频、视频等)需要
permission.READ_EXTERNAL_STORAGE
, 在Android 33后被细分出了permission.READ_MEDIA_VIDEO
,permission.READ_MEDIA_IMAGES
,permission.READ_MEDIA_AUDIO
总结
- Android 10(API 级别 29)以后:
android.permission.WRITE_EXTERNAL_STORAGE
默认无效,但是可以使用android:requestLegacyExternalStorage="true"
过度。 - Android 11(API 级别 30)以后:
android:requestLegacyExternalStorage="true"
开始无效了,但是可以通过permission.MANAGE_EXTERNAL_STORAGE
获取全部文件的读写权限,或者使用context.getExternalFilesDir()
方法获取外部存储空间的应用程序目录/storage/emulated/0/Android/data/包名/file
时,不需要特殊的权限。需要注意:在 Android 12 中,MANAGE_EXTERNAL_STORAGE
权限被修改为更高的保护级别,只有特定的系统应用程序才能获得这个权限,这是一个高危的权限。 - Android 13(API 级别 33)以后:
READ_EXTERNAL_STORAGE
权限被细分,需要获取对应媒体权限permission.READ_MEDIA_VIDEO
,permission.READ_MEDIA_IMAGES
,permission.READ_MEDIA_AUDIO
遇到的问题
1. 第三方相册选择器访问限制
fun checkHasPermission(activity: FragmentActivity,isRequest:Boolean): Boolean {
val hasPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
//**Android 13(API 级别 33),检测并申请对应权限**
activity.hasPermission(
Manifest.permission.READ_MEDIA_VIDEO,
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_AUDIO,
Manifest.permission.READ_EXTERNAL_STORAGE,
isRequest = isRequest
)
} else {
activity.hasPermission(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
isRequest = isRequest
)
}
return hasPermission
}
2. 文件外部存储
方法1: Environment.getExternalStorageDirectory()
使用 context.getExternalFilesDir()
代替;
- 优点:不需要权限申请。
- 缺点:app删除的时候会一起删除,所以重要的媒体文件需要你使用新的媒体方法进行保存。
方法2:获取android.permission.WRITE_EXTERNAL_STORAGE
- 优点:这种方法可以继承老的数据,同时app删除的时候数据不会被删除,
- 缺点:权限太敏感,需要用户跳转对应设置界面手动打开
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
if (!Environment.isExternalStorageManager()) {
//调到对应设置进行处理
try {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.addCategory("android.intent.category.DEFAULT")
intent.data = Uri.parse(String.format("package:%s", context.packageName))
context.startActivity(intent)
} catch (e: Exception) {
val intent = Intent()
intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
context.startActivity(intent)
}
}