美文网首页AndroidIT技术android
Android 11 存储权限适配指南及方案

Android 11 存储权限适配指南及方案

作者: Android轮子哥 | 来源:发表于2020-09-02 11:57 被阅读0次

    前言

    • 首先 Android 的权限大致分为三种:

    • 普通权限:只需要在清单文件中注册即可

    • 危险权限:需要在代码中动态申请,以弹系统 Dialog 的形式进行请求

    • 特殊权限:需要在代码中动态申请,以跳系统 Activity 的形式进行请求

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

    • 从危险权限到特殊权限,这不单单是权限的属性发生了变化,还是申请方式的发生了不同

    Android 10.0 以下存储权限适配

    • 升级 targetSdkVersion
    android 
        defaultConfig {
            targetSdkVersion 23
        }
    }
    
    • 添加清单权限
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    • 代码动态申请
    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("写入文件成功");
        }
    }
    
    • 需要注意的是,如果 targetSdkVersion >= 29 上,还需要在清单文件中加上
    <application
        android:requestLegacyExternalStorage="true">
    
    • 否则就算申请了存储权限,在安卓 10.0 的设备上将无法正常读写外部存储上的文件

    Android 11 及以上申请存储权限

    • 升级 targetSdkVersion
    android 
        defaultConfig {
            targetSdkVersion 30
        }
    }
    
    • 添加清单权限
    <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" />
    
    • 代码动态申请
    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 {
                    startActivityForResult(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION), 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("写入文件成功");
        }
    }
    

    解决方案

    • 看到这里,可能大家心里就会有一些想法了:

      • 申请个权限还要写那么多代码,感觉心好累!

      • 为什么那么麻烦?有没有更简单的写法或方式?

    • 答案当然是有了,并且还是一句代码就能搞定

    XXPermissions.with(MainActivity.this)
            // 不适配 Android 11 可以这样写
            //.permission(Permission.Group.STORAGE)
            // 适配 Android 11 需要这样写,这里无需再写 Permission.Group.STORAGE
            .permission(Permission.MANAGE_EXTERNAL_STORAGE)
            .request(new OnPermission() {
    
                @Override
                public void hasPermission(List<String> granted, boolean all) {
                    if (all) {
                        ToastUtils.show("获取存储权限成功");
                    }
                }
    
                @Override
                public void noPermission(List<String> denied, boolean never) {
                    if (never) {
                        ToastUtils.show("被永久拒绝授权,请手动授予存储权限");
                        // 如果是被永久拒绝就跳转到应用权限系统设置页面
                        XXPermissions.startPermissionActivity(MainActivity.this, denied);
                    } else {
                        ToastUtils.show("获取存储权限失败");
                    }
                }
            });
    
    • 惊不惊喜意不意外开不开心?有了这款框架,你几乎可以零成本适配 Android 11 存储新特性,万万没想到版本适配原来可以这么简单。以后逢人就吹,自从适配了 Android 11,腰不酸了,腿不疼了,走路也越来越有劲了,感觉一下子年轻了十岁!欧耶!得劲!

    点击此处直达 Github 查看

    Android技术分享Q群:78797078

    相关文章

      网友评论

        本文标题:Android 11 存储权限适配指南及方案

        本文链接:https://www.haomeiwen.com/subject/tucejktx.html