适配Android O及以上版本,如何解决targetApi=27后读写存储权限失效问题?
Android O(API 26+)外部存储读写权限适配指南
嘿,这个问题我太熟悉了!Android 8.0(API 26)开始,系统对存储权限的逻辑做了关键调整,这就是你之前的代码突然失效的原因,咱们一步步理清楚:
为什么旧代码不再生效?
在API 26及以上版本,WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE同属于「STORAGE」权限组,系统会自动关联这两个权限:
- 当用户授予其中一个权限时,另一个权限会被系统自动授予;
- 如果你同时申请两个权限,系统只会弹出一次授权弹窗(显示“允许应用访问设备上的照片、媒体和文件”),但在
onRequestPermissionsResult()回调中,可能只会返回READ_EXTERNAL_STORAGE的授权结果,WRITE权限的结果看起来像是未被授予,但实际上系统已经自动给你了。
适配API 26+的正确做法
1. 简化权限申请代码
你只需要申请READ_EXTERNAL_STORAGE权限就足够了,系统会自动附带授予WRITE_EXTERNAL_STORAGE权限:
private static final int REQUEST_STORAGE_PERMISSION = 100; // 检查并申请权限 public void checkStoragePermission(Context context) { if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION); } else { // 权限已授予,执行存储操作 performStorageTasks(); } }
2. 正确处理权限回调
在onRequestPermissionsResult()中,只需要判断READ_EXTERNAL_STORAGE的授权结果即可,因为WRITE权限已经自动同步:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_STORAGE_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // READ权限已授予,WRITE权限也自动生效 performStorageTasks(); } else { // 权限被拒绝,提示用户开启权限 Toast.makeText(this, "需要存储权限才能访问媒体文件", Toast.LENGTH_SHORT).show(); } } }
3. 权限检查的正确姿势
后续在使用存储功能前,只需要检查READ_EXTERNAL_STORAGE的权限状态,无需单独检查WRITE:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // 可以放心读写外部存储 }
额外提醒(针对更高版本)
如果你的应用后续要适配Android 10(API 29)及以上,还会遇到「分区存储(Scoped Storage)」的限制,不过这是另一个话题了,当前针对API 26-28的场景,上面的方案完全够用。
内容的提问来源于stack exchange,提问作者svkaka
相关产品推荐
相关产品推荐

