Android 存储权限适配指南

(1)targetSdkVersion

想要了解权限,最好还是要对Android系统版本和API等级有一定的了解,才能知道Android在哪个系统版本对权限有所变化。
具体可参考如下文章Android 系统版本和 API 等级对应关系表

(2)Android权限分类

  • 普通权限:只需要在清单文件中注册即可
  • 危险权限:需要在代码中动态申请,以弹系统 Dialog 的形式进行请求
  • 特殊权限:需要在代码中动态申请,以跳系统 Activity 的形式进行请求

而我们今天要讲的主题,是关于存储权限,在 Android 6.0 之后就变成了危险权限,而到了 Android 11 上面变成了特殊权限,而最明显的区别是一个是通过 Dialog 展示给用户看,另外一个是通过 Activity 展现给用户看。

(A)6.0之后的危险权限界面

6.0权限
(B)Android 11®之后的特殊权限界面

11权限

(4)Android 10.0 以下存储权限适配

(A)升级 targetSdkVersion

android 
    defaultConfig {
        targetSdkVersion 23
    }
}

(B)添加清单权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

(C)代码动态申请

public final class PermissionActivity extends AppCompatActivity {

    private static final int REQUEST_CODE = 1024;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestPermission();
    }

    private void requestPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 先判断有没有权限
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                writeFile();
            } else {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
            }
        } else {
            writeFile();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                writeFile();
            } else {
                ToastUtils.show("存储权限获取失败");
            }
        }
    }

    /**
     * 模拟文件写入
     */
    private void writeFile() {
        ToastUtils.show("写入文件成功");
    }
}

(D)需要注意的是,如果 targetSdkVersion >= 29 上,还需要在清单文件中加上

<application
    android:requestLegacyExternalStorage="true">

否则就算申请了存储权限,在安卓 10.0 的设备上将无法正常读写外部存储上的文件。

(4)Android 11 申请存储权限

(A)升级 targetSdkVersion

android 
    defaultConfig {
        targetSdkVersion 30
    }
}

(B)添加清单权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

(C)代码动态申请

public final class PermissionActivity extends AppCompatActivity {

    private static final int REQUEST_CODE = 1024;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestPermission();
    }

    private void requestPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            // 先判断有没有权限
            if (Environment.isExternalStorageManager()) {
                writeFile();
            } else {
                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                intent.setData(Uri.parse("package:" + context.getPackageName()));
                startActivityForResult(intent, REQUEST_CODE);
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 先判断有没有权限
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                writeFile();
            } else {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
            }
        } else {
            writeFile();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                writeFile();
            } else {
                ToastUtils.show("存储权限获取失败");
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (Environment.isExternalStorageManager()) {
                writeFile();
            } else {
                ToastUtils.show("存储权限获取失败");
            }
        }
    }

    /**
     * 模拟文件写入
     */
    private void writeFile() {
        ToastUtils.show("写入文件成功");
    }
}

(5)使用三方Jar来简单申请权限

XXPermissions.with(this)
        // 不适配 Android 11 可以这样写
        //.permission(Permission.Group.STORAGE)
        // 适配 Android 11 需要这样写,这里无需再写 Permission.Group.STORAGE
        .permission(Permission.MANAGE_EXTERNAL_STORAGE)
        .request(new OnPermissionCallback() {

            @Override
            public void onGranted(List<String> permissions, boolean all) {
                if (all) {
                    toast("获取存储权限成功");
                }
            }

            @Override
            public void onDenied(List<String> permissions, boolean never) {
                if (never) {
                    toast("被永久拒绝授权,请手动授予存储权限");
                    // 如果是被永久拒绝就跳转到应用权限系统设置页面
                    XXPermissions.startPermissionActivity(MainActivity.this, permissions);
                } else {
                    toast("获取存储权限失败");
                }
            }
        });

(6)Android 13 申请存储权限

从Android 13开始,如果你的应用targetSdk指定到了33或以上,那么READ_EXTERNAL_STORAGE权限就完全失去了作用,申请它将不会产生任何的效果。

与此同时Google新增了READ_MEDIA_IMAGES、READ_MEDIA_VIDEO和READ_MEDIA_AUDIO这3个运行时权限,分别用于管理手机的照片、视频和音频文件。

(A)升级 targetSdkVersion

android 
    defaultConfig {
        targetSdkVersion 33
    }
}

(B)添加清单权限

<!--  一般来说,允许用户自定义头像的app都需要这个权限  -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"
    android:minSdkVersion = "33"/>
<!--  如果你想开发音乐播放器之类需要获取音频的app,加上这个权限  -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"
    android:minSdkVersion = "33"/>
<!--  如果你想开发视频编辑器之类需要获取视频的app,加上这个权限  -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"
    android:minSdkVersion = "33"/>
<!--  向前兼容  -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="32" />

(C)代码动态申请

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
   ActivityCompat.requestPermissions( activity,new String[]{
           READ_MEDIA_IMAGES,
           READ_MEDIA_AUDIO,
           READ_MEDIA_VIDEO
   },MEDIA_READ_REQUEST_CODE);
}else{
   ActivityCompat.requestPermissions( activity,new String[]{
           READ_EXTERNAL_STORAGE
   },MEDIA_READ_REQUEST_CODE);
}

(D)Android 13自带的文件选择器

Android 13除了修改对媒体文件访问权限外,还为用户提供了一种全新的媒体文件选择器,让其无需向应用授予对整个媒体库的访问权限,也解决了以往的版本不支持多选的问题。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
    // 打开Android 13自带的媒体文件选择器(默认单选)
    Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
    // 如果想多选,就加上这行代码,其中MediaStore.getPickImagesMaxLimit()代表设备的Provider最大支持的多选数量
    intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, Math.min(10,MediaStore.getPickImagesMaxLimit()));
    // 如果只能选择视频,加上这行代码
    intent.setType("video/*");
    // 如果想只选择图片,加上这行代码
    intent.setType("image/*");
    // 如果想限定某种格式的图片或视频,可以把上边的*改成gif或者mp4
    intent.setType("image/gif");
    startActivityForResult(intent, PHOTO_PICKER_MULTI_SELECT_REQUEST_CODE);
}
  • 15
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
Android 中,使用存储权限可以让应用程序访问设备的文件系统,包括读取和写入文件。为了使用存储权限,您需要在 AndroidManifest.xml 文件中声明相应的权限。以下是声明存储权限的示例: ``` <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application ... </application> </manifest> ``` 在 Android 6.0 及以上版本中,存储权限被称为运行时权限,需要在应用程序运行时请求用户授权。您可以使用以下代码请求存储权限: ``` if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE); } ``` 当用户授权或拒绝权限请求时,将调用 onRequestPermissionsResult() 方法。您可以在此方法中检查用户是否授权了所需的权限: ``` @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限已授予 } else { // 权限被拒绝 } return; } } } ``` 请注意,为了保护用户的个人数据,您应该只请求应用程序需要的最少权限。在您的应用程序中使用存储权限时,请遵循最佳实践,例如仅访问应用程序专用目录,而不是整个文件系统。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪舞飞影

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值