Android6.0动态权限申请

来源:互联网 发布:阿里云服务器 访问慢 编辑:程序博客网 时间:2024/05/22 12:30
一、Android 6.0动态权限说明

        一个Android应用默认情况下是不拥有任何权限的, 也就是说, 在默认情况下, 一个应用是没有权利去进行一些可能会造成不好影响的操作的。这些不好的影响可能是对其它应用、操作系统、或者是用户。如果应用需要一些额外的能力,它就需要在AndroidManifest.xml中静态地声明相应的权限。
 
        如果应用没有在manifest中声明权限,却使用了相应的功能,在调用到相应功能的时候,将会抛出异常。比如程序要发送一个请求,却忘记加Internet权限,那么在发送这个请求的时候程序就会抛出异常,一般不会catch这个异常,所以程序直接就崩溃了:
Caused by: java.lang.SecurityException: Permission denied (missing INTERNET permission?)
 
        在Android 6.0 (API 23) 发布之前, 所有的权限都在安装应用的时候显示给用户,用户选择安装则表示全部接受这些权限, 之后无法撤销对这些权限的授权。从Android 6.0开始,一部分比较危险的权限需要在程序运行时显式弹框,请求用户授权,这应该是谷歌为了避免一些官司并且考虑到了用户的需求。至于什么时候弹这个框,由应用程序自己决定。对于其他普通权限,认为不是很危险,所以仍然保持原来的做法,在用户安装应用程序时就予以授权。还需要注意的是:对于应用的危险权限,在手机系统设置中,用户可以选择性地进行授权或者关闭。
       
        权限是分组的,同一个组的权限申请其中一个,同组的权限就全部申请了。下面我把需要单独申请的9个权限分组列出来,供大家查阅:

特殊权限组:1.CALENDAR 日历;2.CAMERA 相机;3.CONTACTS 联系人;4.LOCATION 定位;5.MICROPHONE 麦克相关,比如录音;6.PHONE 手机状态;7.SENSORS 传感器;8.SMS 短信;9.STORAGE 存储权限。



二、我遇到的问题以及准备工作

        最近一个项目中要使用户点击图片可以下载到本地,我自己手机还是5.0的系统没有遇到问题。但是在6.0的手机上一直提示下载失败,出现FileNotFoundException:EACCES (permission denied)的log。我就纳闷了为何就它不行呢!最后才想起来应该是6.0权限的问题。

1.我先检查了我的AndroidManifest.xml是否已经有读写权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
2.确定我的权限加上以后,我开始研究怎么动态添加。这里主要说明一下在运行时请求权限涉及的几个方法:
(1)权限检查:
    // 检查权限    ContextCompat.checkSelfPermission(Context context, String permission)
返回值:(android.content.pm.PackageManager中的常量):
有权限:PackageManager.PERMISSION_GRANTED
无权限:PackageManager.PERMISSION_DENIED
当应用需要用到危险权限时,在执行权限相关代码前,使用该方法判断是否拥有指定权限。有权限,则继续执行设计需要的权限的代码;无权限,则向用户请求授予权限。
(2)解释权限:
// 解释权限ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission)
当检测到应用没有指定的权限时,调用此方法向用户请求权限。调用此方法将弹出权限请求对话框询问用户“允许”或“拒绝”指定的权限。
(3)请求权限:
请求权限的结果返回和接收一个Activity的返回类似,重写FragmentActivity或Fragment中的onRequestPermissionsResult(…)方法。
/** * 处理权限请求结果 * * @param requestCode *          请求权限时传入的请求码,用于区别是哪一次请求的 * * @param permissions *          所请求的所有权限的数组 * * @param grantResults *          权限授予结果,和 permissions 数组参数中的权限一一对应,元素值为两种情况,如下: *          授予: PackageManager.PERMISSION_GRANTED *          拒绝: PackageManager.PERMISSION_DENIED */@Overridepublic void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {    // ...}
注意:
  • 权限参数传入的是数组,可以调用该方法一次请求多个权限;
  • 传入的权限数组参数以单个具体权限为单位,但弹框询问用户授权时,属于同一权限组的权限将自动合并询问授权一次
  • 请求的权限必须事先在 AndroidManifest.xml 中有声明,否则调用此方法请求时,将不弹框,而是直接返回“拒绝”的结果;
  • 第一次请求权限时,用户点击了“拒绝”,第二次再请求该权限时,对话框将出现“不再询问”复选框,如果用户勾选了“不再询问”并点击了“拒绝”,则之后再请求此权限组时将不弹框,而是直接返回“拒绝”的结果。

    三、关键代码
            我给大家分两种场合说明使用方法,避免大家重复踩坑!
    1.在Activity中直接使用:
        public static void checkForPermission(Context mContext) {        /**         * 动态获取权限,Android 6.0 新特性,一些保护权限,除了要在AndroidManifest中声明权限,还要使用如下代码动态获取         */        if (Build.VERSION.SDK_INT >= 23) {            int REQUEST_EXTERNAL_STORAGE = 1;            String[] PERMISSIONS_STORAGE = {                    Manifest.permission.READ_EXTERNAL_STORAGE,                    Manifest.permission.WRITE_EXTERNAL_STORAGE            };            int permission = ActivityCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE);            if (permission != PackageManager.PERMISSION_GRANTED) {                // We don't have permission so prompt the user                ActivityCompat.requestPermissions(                        (Activity) mContext,                        PERMISSIONS_STORAGE,                        REQUEST_EXTERNAL_STORAGE                );            }        }    }
    2.在工具类中使用的话,千万注意在Manifest.permission.READ_EXTERNAL_STORAGE 前面必须加上android. 不然会报红。
     public static void checkForPermission(Context mContext) {        /**         * 动态获取权限,Android 6.0 新特性,一些保护权限,除了要在AndroidManifest中声明权限,还要使用如下代码动态获取         */        if (Build.VERSION.SDK_INT >= 23) {            int REQUEST_EXTERNAL_STORAGE = 1;            String[] PERMISSIONS_STORAGE = {                    android.Manifest.permission.READ_EXTERNAL_STORAGE,                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE            };            int permission = ActivityCompat.checkSelfPermission(mContext, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);            if (permission != PackageManager.PERMISSION_GRANTED) {                // We don't have permission so prompt the user                ActivityCompat.requestPermissions(                        (Activity) mContext,                        PERMISSIONS_STORAGE,                        REQUEST_EXTERNAL_STORAGE                );            }        }    }
  • 前面两种情况中调用申请的方法后的执行情况如下图:
  • 3.如果要做一些有好的提示或者其他操作的话,可以在Activity的回调中添加。
        @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        switch (requestCode) {            case REQUEST_EXTERNAL_STORAGE:                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                    Toast.makeText(this, "已获得app读取权限",Toast.LENGTH_SHORT);                } else {                    Toast.makeText(this, "未获得app读取权限,请您手动设置权限后重试",Toast.LENGTH_SHORT);                }                break;        }    }
    四、最后说明一下用户点击“拒绝”之后的情况
            对于弹窗中出现的权限申请,如果用户点击拒绝后,就不会再次出现申请的弹窗。这时如果用户要允许这个权限,只能主动到设置里面修改,重新选择允许后就可以正常使用了。我使用的是小米X,具体路径是设置-授权管理-应用授权管理,找到当前的app,点击需要修改的权限名称,进行重新选择即可(有允许、询问、和拒绝三个选项)。

  • 原创粉丝点击