这里我将介绍:
*1. 动态权限的基本使用(包括个人理解)*
*2. 动态权限使用时,我们需要去注意什么*
先解释 再上例子
为了用户体验考虑,Android6.0之后,希望当APP运行到需要被授予某项权限时,才会去提示用户开启某项权限,而不是像以前那样,直接在启动页就全部请求授予,这就要求我们,在需要时提示用户开启权限并对权限请求结果进行回调监听。
-
需要知道的
-
两个与权限有关的变量:
PackageManager.PERMISSION_GRANTED = 0 //表示授予权限; PackageManager.PERMISSION_DENIED = -1 //表示权限未开启;
-
运行权限检测的三种方式:
方式一: public static int checkSelfPermission(Activity activity,String writeContacts) { return PermissionChecker.checkSelfPermission(activity, writeContacts); } 方式二: public static int checkSelfPermission(Activity activity,String writeContacts) { return ContextCompat.checkSelfPermission(WelcomeActivity.this,Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED); } 方式三: public static boolean checkSelfPermission() { PackageManager pm = this.getPackageManager(); for (String auth : authBaseArr) { //注意,这里是只要有一个权限未通过,则返回false,并不能对具体某个权限做区分 if (pm.checkPermission(auth, this.getPackageName()) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; }
-
请求开启权限的弹窗显示:
ActivityCompat.requestPermissions(mactivity, new String[] { CALL_PHONE ,CAMERA },REQUEST_CODE);
注意:一次请求多个权限会有bug,当该次权限弹窗中有一个未被授予权限,那么再次执行该代码时,只会一直提示用户需要获取第一项权限,但是此时即使用户点击允许,依然会不断提示请求开启第一项权限(实则是需要开启后边的某项权限),所以还是每次都只请求一个权限稳妥!!! 例如你可以这样写:
private void baiduPermission() { boolean canInitBaidu = true; // 申请权限 if (android.os.Build.VERSION.SDK_INT >= 23) { pm = this.getPackageManager(); if (pm.checkPermission(authBaseArr[0], this.getPackageName()) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, authBaseRequestCode); canInitBaidu = false; } if (pm.checkPermission(authBaseArr[1], this.getPackageName()) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, authBaseRequestCode); canInitBaidu = false; } } if (canInitBaidu) { initLoc(); } }
-
权限请求结果监听:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == BaiDuRequest && grantResults.length > 0 && grantResults[0]==-1){ UtilsW.showMessageOKCancel(mactivity, "温馨提示", " 当前操作需要开启“XXX”权限,您可到设置的权限管理中,修改该应用的相关权限。", null); } }
注意:这里使用了grantResults.length > 0 ,这是为防止同时有两个requestPermissions(new String[] { XXX},RequestCode);被调用,而引起的crash问题,grantResults[0]==-1(也就是grantResults[0]==PackageManager.PERMISSION_DENIED),表示用户拒绝了该项权限,那如果要申请多个权限怎么办?,我们可以在第一个成功后再去申请,如下:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == BaiDuRequest && grantResults.length > 0 && grantResults[0]==-1){ UtilsW.showMessageOKCancel(mactivity, "温馨提示", " 当前操作需要开启“定位”和“存储”权限,您可到设置的权限管理中,修改该应用的相关权限。", null); } else if (ACCESS_FINE_LOCATION.equalsIgnoreCase(permissions[0]) && grantResults.length > 0 && grantResults[0]== 0) { ActivityCompat.requestPermissions(mactivity, new String[] {WRITE_EXTERNAL_STORAGE },BaiDuRequest); } }
对于非Android6.0版本的手机,我们还是可以在AndroidManifest.xml中,直接设置权限的(如:<uses-permission android:name="android.permission.READ_PHONE_STATE"/>),在启动APP时,就会有弹窗提示用户给予权限了,二者虽有重复,但谁让咱们大Android越来越贴心呢;
-
shouldShowRequestPermissionRationale作用:
- 第一次请求权限时,用户拒绝了,下一次:shouldShowRequestPermissionRationale() 返回 true,应该显示一些为什么需要这个权限的说明;
- 第二次请求权限时,用户拒绝了,并选择了“不在提醒”的选项时:shouldShowRequestPermissionRationale() 返回 false
- 设备的策略禁止当前应用获取这个权限的授权:shouldShowRequestPermissionRationale() 返回 false
注意:上面的:第二次请求权限时,才会有“不在提醒”的选项,如果用户一直拒绝,并没有选择“不在提醒”的选项,下次请求权限时,会继续有“不在提醒”的选项
应用方面举例:
在获取DeviceID时,我们有很多方法,比如这样:
/** * 获取DeviceId (IMEI方式) * 其他获取DeviceId方式: http://blog.csdn.net/u014651216/article/details/50767326 */ public static String getDeviceID(Activity activity) { return ((TelephonyManager)activity.getSystemService(activity.TELEPHONY_SERVICE)).getDeviceId(); }
但是直接这样调用会报错的:
SecurityException: getDeviceId: Neither user 10282 nor current process has android.permission.READ_PHONE_STATE.
我们需要先判断是否有读取电话状态的动态权限,然后去申请该权限,如下:
//电话状态读取的动态权限校验 if (Utils.checkSelfPermission(this,READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { Utils.showMessageOKCancel(this,"提示:\n\n该应用权限已关闭。\n开启方式:点击确定后,您可到“权限”中,开启该应用的“电话”权限。", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); //未开启该权限,引导用户到开启该项权限的页面 intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } }); return ;
-
或者直接再次申请权限:
int permissionNum = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE); //检测某项权限是否开启
if (permissionNum != PackageManager.PERMISSION_GRANTED) { //若该权限未开启
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_READ_PHONE_STATE);
} //但这种若用户在第一次弹窗时,勾选了不再提醒,将不会再次有该项提示了
.