我们知道从Android 6.0(API 23) 开始,Google在Android上引入了动态权限模式,即用户可在应用运行时管理权限, 这种模式让用户能够更好地了解和控制权限,用户可为所安装的各个应用分别授予或撤销权限。 但是对于开发者来说,为了适配Android 6.0(API 23)及以上版本,除了在AndroidManifest.xml中去声明相关权限, 对于Android官网中划分的危险权限 https://developer.android.com/guide/topics/permissions/overview, 还需要在代码中判断该应用是否被授予权限,以保证程序的正常运行。

(1)ContextCompat.checkSelfPermission()

       ContextCompat.checkSelfPermission()方法来检测某个权限是否被授予

(2) ActivityCompat.requestPermissions()

       ActivityCompat.requestPermissions()方法用来动态申请权限,我们在调用requestPermission()方法去申请权限时,系统会弹出权限申请提示框,可以同意授予,用户可以拒绝,如果用户选择了拒绝,并且勾选了不再提示,那么再次调用ActivityCompat.requestPermissions()方法申请该权限时,系统就不会弹出权限申请的弹窗了。

(3)onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 回调方法

       无论用户同意授权,还是拒绝了授权,都会在onReuqestPermissionResult()回调方法中返回用户的选择结果。

(4)shouldShowRequestPermissionRationale()

       前面说过,使用ActivityCompat.requestPermissions()方法用来动态申请权限,系统会弹出权限申请提示框,可以同意授予,用户可以拒绝,如果用户选择了拒绝,并且勾选了不再提示,那么再次调用ActivityCompat.requestPermissions()方法申请该权限时,系统就不会弹出权限申请的弹窗了,那么我们该怎么告知用户需要去开启某个权限呢?
       这个时候就要引出我们今天说的主角shouldShowRequestPermissionRationale(),该方法来判断用户是否拒绝过授予权限,并且勾选了不再提示操作。如果shouldShowRequestPermissionRationale()返回true,则说明之前用户绝拒绝了授权,并且勾选了不再提示,这个时候应用可以提示用户去设置中开启权限。

介绍了上面的几个方法,下面给出之前我们项目中实现高德地图定位,动态申请权限的代码
高德地图定位需要动态申请的权限有:

            
 /**     * 初始化高德定位     */    private void initGaoDeLocation() {        if (Build.VERSION.SDK_INT >= 23) {            if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)                    != PackageManager.PERMISSION_GRANTED) {                if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { //用户已拒绝过一次                    //提示用户如果想要正常使用,要手动去设置中授权。                    ToastUtil.showShort(mActivity, "请到设置-应用管理中开启此应用的读写权限");                } else {                    ActivityCompat.requestPermissions(mActivity,                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE},                            PERMISSION_REQUEST_CODE_LOCATION);                }            } else if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_FINE_LOCATION)                    != PackageManager.PERMISSION_GRANTED) {                if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, Manifest.permission.ACCESS_FINE_LOCATION)) { //用户已拒绝过一次                    //提示用户如果想要正常使用,要手动去设置中授权。                    ToastUtil.showShort(mActivity, "请到设置-应用管理中开启此应用的定位权限");                } else {                    ActivityCompat.requestPermissions(mActivity,                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE},                            PERMISSION_REQUEST_CODE_LOCATION);                }            } else if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.READ_PHONE_STATE)                    != PackageManager.PERMISSION_GRANTED) {                if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, Manifest.permission.READ_PHONE_STATE)) { //用户已拒绝过一次                    //提示用户如果想要正常使用,要手动去设置中授权。                    ToastUtil.showShort(mActivity, "请到设置-应用管理中开启此应用的电话权限");                } else {                    ActivityCompat.requestPermissions(mActivity,                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE},                            PERMISSION_REQUEST_CODE_LOCATION);                }            } else {                DialogUtil.showUnCancelableProgress(mActivity, "正在进行定位");                gaoDeLocation();            }        } else {            DialogUtil.showUnCancelableProgress(mActivity, "正在进行定位");            gaoDeLocation();        }    }    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        switch (requestCode) {            case PERMISSION_REQUEST_CODE_LOCATION:                if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {                    ToastUtil.showShort(mActivity, "请在到设置-应用管理中开启此应用的储存授权");                    return;                }                if (grantResults[1] != PackageManager.PERMISSION_GRANTED) {                    ToastUtil.showShort(mActivity, "请在到设置-应用管理中开启此应用的定位权限");                    return;                }                if (grantResults[2] != PackageManager.PERMISSION_GRANTED) {                    ToastUtil.showShort(mActivity, "请在到设置-应用管理中开启此应用的获取电话权限");                    return;                }                DialogUtil.showUnCancelableProgress(mActivity, "正在进行定位");                gaoDeLocation();                break;        }    }

       但是我们今天的标题是Android 动态权限申请之 shouldShowRequestPermissionRationale方法异常,所以回到我们的主题,由于Android系统的碎片化,在国内,不同手机厂商都对Android系统都做了不同的定制,上面的代码在大部分手机上测试没有任何问题,直到某天在公司的测试机 努比亚 Z17 mini S,Android系统版本是Android 7.1.1,发现首次执行该段代码,shouldShowRequestPermissionRationale()就返回true,
也就是说在这个努比亚手机上,用户没有拒绝过授予权限,并且也没有勾选不再提示,shouldShowRequestPermissionRationale()也会返回true,所以上面的这段代码,永远也不会执行到ActivityCompat.requestPermissions(mActivity,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE},
PERMISSION_REQUEST_CODE_LOCATION);
永远不会弹出权限授予弹窗。

所以为了适配努比亚手机,我将上述代码改成了如下:

  /**     * 初始化高德定位     */    private void initGaoDeLocation() {        if (Build.VERSION.SDK_INT >= 23) {            if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)                    != PackageManager.PERMISSION_GRANTED) {                ActivityCompat.requestPermissions(mActivity,                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE},                        PERMISSION_REQUEST_CODE_LOCATION);            } else if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_FINE_LOCATION)                    != PackageManager.PERMISSION_GRANTED) {                ActivityCompat.requestPermissions(mActivity,                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE},                        PERMISSION_REQUEST_CODE_LOCATION);            } else if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.READ_PHONE_STATE)                    != PackageManager.PERMISSION_GRANTED) {                ActivityCompat.requestPermissions(mActivity,                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE},                        PERMISSION_REQUEST_CODE_LOCATION);            } else {                DialogUtil.showUnCancelableProgress(mActivity, "正在进行定位");                 gaoDeLocation();            }        } else {            DialogUtil.showUnCancelableProgress(mActivity, "正在进行定位");             gaoDeLocation();        }    }

不再使用shouldShowRequestPermissionRationale,只要判断到权限没有被授予,就去调用 ActivityCompat.requestPermissions()去申请权限;如果用户选择了拒绝,并且勾选了不再提示,调用ActivityCompat.requestPermissions(),虽然不会弹出权限申请弹窗,但是会直接
回调onRequestPermissionResult()方法,我们只需要在该回调方法中去提示用户去设置中开启权限即可。

更多相关文章

  1. Android(安卓)版本适配6.0到9.0
  2. Android(安卓)root 原理
  3. 2010最佳Android和iPhone/iPad游戏应用出炉
  4. Android中文件读写错误 open failed: ENOENT (No such file or d
  5. Android通过代码获取ROOT权限
  6. ubuntu下运行android emulator权限不够解决方法
  7. android 模拟器 sdcard权限修改
  8. Android系统权限和root权限的获取以及应用权限列表
  9. Android(安卓)M 运行时权限

随机推荐

  1. android study ------ HAL ---> light se
  2. Android程序示例
  3. Android:VerticalSeekBar
  4. Android—复选框和单选框使用
  5. Android(安卓)自定义ProgressBar--进度自
  6. Android: java.lang.ClassCastException:
  7. android 序列化传值
  8. android获取mac地址
  9. Android(安卓)LruCache & DiskLruCache c
  10. Android(安卓)UI控件详解-CheckBox(多选