android M版本以上权限管理已经变为动态申请了,即用到啥就问你要不要同意,不同意就用不了。如果一个功能一次要用多个权限的话,就会挨个问你要不要同意,其中有一个不同意,就使用不了改功能。这里查阅了网上很多文章,写了一个比较简洁实用的工具类,可以实现一个,多个权限动态申请(而不会导致crash),之前测试了很多方法,多权限申请,同意一个,然后拒绝另一个,容易crash,现在这个工具类可以避免这个问题。先上了代码再说(请问代码是谁?TT):
工具类代码
public class PermissionUtils {
private static final String TAG = "PermissionUtils===";
public static final int CODE_CALL_PHONE = 1;//打电话
public static final int CODE_CAMERA_AND_EXTERNAL_STORAGE = 2;//拍照,获取相册
public static final String PERMISSION_CALL_PHONE = Manifest.permission.CALL_PHONE;
public static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;
public static final String PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE;
public static final String PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;
public interface PermissionGrant {
void onPermissionGranted(int requestCode);
}
/**
* 一次申请多个权限,当然也可以是一个,兼容模式
*/
public static void requestMultiPermissions(Activity activity, PermissionGrant grant,String[] permissions,int requestCode) {
List<String> permissionsList = getNoGrantedPermission(activity,permissions);
if (permissionsList == null) {
return;
}
Log.d("test======", "permissionsList:" + permissionsList.size());
if (permissionsList.size() > 0) {
ActivityCompat.requestPermissions(activity, permissionsList.toArray(new String[permissionsList.size()]), requestCode);
} else {
grant.onPermissionGranted(requestCode);
}
}
private static void showMessageOKCancel(Activity context, String message, DialogInterface.OnClickListener okListener) {
final CommonDialog commonDialog = new CommonDialog(context);
commonDialog.setMessage(message);
commonDialog.setPositiveBtnListener(okListener);
commonDialog.show();
}
public static void requestPermissionsResult(Activity activity,int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults, PermissionGrant permissionGrant) {
if (activity == null) {
return;
}
Log.d(TAG, "onRequestPermissionsResult permissions length:" + permissions.length);
ArrayList<String> notGranted = new ArrayList<>();
for (int i = 0; i < permissions.length; i++) {
Log.d(TAG, "permissions: [i]:" + i + ", permissions[i]" + permissions[i] + ",grantResults[i]:" + grantResults[i]);
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
notGranted.add(permissions[i]);
}
}
if (notGranted.size() == 0) {
permissionGrant.onPermissionGranted(requestCode);
} else {
openSettingActivity(activity, "该功能需要相应权限才能使用,确定前往设置页面打开吗?");
}
}
private static void openSettingActivity(final Activity activity, String message) {
showMessageOKCancel(activity, message, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Log.d(TAG, "getPackageName(): " + activity.getPackageName());
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
intent.setData(uri);
activity.startActivity(intent);
}
});
}
/**
* @param activity
* @return
*/
public static ArrayList<String> getNoGrantedPermission(Activity activity,String[] requestPermissions) {
ArrayList<String> permissions = new ArrayList<>();
for (int i = 0; i < requestPermissions.length; i++) {
String requestPermission = requestPermissions[i];
int checkSelfPermission = -1;
try {
checkSelfPermission = ActivityCompat.checkSelfPermission(activity, requestPermission);
} catch (RuntimeException e) {
Toast.makeText(activity, "请前往设置页面打开应用所需权限", Toast.LENGTH_SHORT).show();
Log.e(TAG, "RuntimeException:" + e.getMessage());
return null;
}
if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
permissions.add(requestPermission);
LogApi.DebugLog("test======","requestPermission===:"+requestPermission);
/*
boolean rationale=ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission);
1. 第一次请求权限时,用户拒绝了,下一次:shouldShowRequestPermissionRationale() 返回 true,应该显示一些为什么需要这个权限的说明
2.第二次请求权限时,用户拒绝了,并选择了“不在提醒”的选项时:shouldShowRequestPermissionRationale() 返回 false
3. 设备的策略禁止当前应用获取这个权限的授权:shouldShowRequestPermissionRationale() 返回 false
*/
}
}
return permissions;
}
}
思路:传入所需权限数组,遍历数组每个权限是否被同意即checkSelfPermission是否返回0如果值不为0,则把这些被拒绝的权限放到新数组里面,如果不筛选,而是把一开始所有权限再次进行多权限申请,这里面如果包含了被同意的和被拒绝的,那么会导致crash,调用 requestPermissions进行新的一轮申请在申请结果里面统计所有申请的权限是否都被同意,如果都被同意,那么可以该干啥干啥了,如果有部分没有被同意,那么跳转到系统设置页面, 让用户手动修改权限。如果用户拒绝手动修改,那么返回最开始申请页面,用户点击相应控件,再次统计没有被同意的权限,进行新一轮申请,往复循环直到最终都同意了,才进入正常功能。针对shouldShowRequestPermissionRationale方法,它一开始返回true,如果用户点击下次不再提示则会返回false。可以根据它的返回值给用户一点提示,本工具并没有用到这个方法,因为这里完全是根据返回权限数组的长度来判断的,即notGranted.size() == 0的话,即说明所有权限都被同意否则,引导用户去设置页面手动打开权限。
调用代码:
//照相和获取相册图片权限
private String[] authVerifyPermissions = {
PermissionUtils.PERMISSION_CAMERA,
PermissionUtils.PERMISSION_READ_EXTERNAL_STORAGE,
PermissionUtils.PERMISSION_WRITE_EXTERNAL_STORAGE
};
//打电话权限
private String[] callVerifyPermissions = {
PermissionUtils.PERMISSION_CALL_PHONE
};
private void choosePicture() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestCameraAndStorage();
return;
}
chooseP();
}
private void callPhone() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestCallPhonePermission();
return;
}
toCall();
}
//申请照相和获取相册图片权限
public void requestCameraAndStorage() {
PermissionUtils.requestMultiPermissions(AuthActivity.this, mPermissionGrant,authVerifyPermissions,PermissionUtils.CODE_CAMERA_AND_EXTERNAL_STORAGE);
}
//申请打电话权限
private void requestCallPhonePermission() {
PermissionUtils.requestMultiPermissions(AuthActivity.this, mPermissionGrant, callVerifyPermissions, PermissionUtils.CODE_CALL_PHONE);
}
private PermissionUtils.PermissionGrant mPermissionGrant = new PermissionUtils.PermissionGrant() {
@Override
public void onPermissionGranted(int requestCode) {
switch (requestCode) {
case PermissionUtils.CODE_CAMERA_AND_EXTERNAL_STORAGE:
chooseP();
break;
case PermissionUtils.CODE_CALL_PHONE:
toCall();
break;
default:
break;
}
}
};
@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
PermissionUtils.requestPermissionsResult(this, requestCode, permissions, grantResults, mPermissionGrant);
}
本文主要参考博客链接:
简书里的小爱_小世界