一、概述
Android6.0由于考虑到安全性,把系统权限收紧了,需要在app程序运行时动态地去向用户申请权限。
二、示例
以申请录音权限为例:
//检查是否有录音权限
boolean isAllGranted = PermissionUtils.checkPermissionAllGranted(this, new
String[]{Manifest.permission.RECORD_AUDIO});
if (isAllGranted) {//如果有录音权限
//do some thing
} else {
//请求录音权限
PermissionUtils.requestPermission(AskForHelpActivity.this, new String[]{Manifest
.permission.RECORD_AUDIO});
}
其中用到了PermissionUtils这个我自己简单封装的工具类
public class PermissionUtils {
public static final int UTILS_PERMISSION_REQUEST_CODE = 8069;//工具类权限请求码
/**
* 检查是否拥有指定的所有权限
*
* @param mContext
* @param permissions
* @return
*/
public static boolean checkPermissionAllGranted(Context mContext, String[] permissions) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(mContext, permission) != PackageManager
.PERMISSION_GRANTED) {
// 只要有一个权限没有被授予, 则直接返回 false
return false;
}
}
//安卓原生权限管理 适配小米等第三方
AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(Context
.APP_OPS_SERVICE);
int checkOp = appOpsManager.checkOp(AppOpsManager.OPSTR_FINE_LOCATION, Process.myUid
(), mContext
.getPackageName());
if (checkOp != AppOpsManager.MODE_IGNORED) {
return false;
}
}
return true;
}
/**
* 一次请求多个权限, 如果其他有权限是已经授予的将会自动忽略掉
*
* @param activity
* @param permissions
*/
public static void requestPermission(Activity activity, String[] permissions) {
ActivityCompat.requestPermissions(activity, permissions, UTILS_PERMISSION_REQUEST_CODE);
}
}
经过本人测试发现v4包下的ContextCompat的checkSelfPermission去动态检测权限时,如果用户已经拒绝了该权限,就算你手动去系统的 应用信息 --> 权限 中开启,小米等第三方还是会在你检测权限时返回flase,即无权限。
因此需要采用Android原生的权限管理(AppOpsManager这个类)来解决这个问题,即上面的这段关键代码(坑的我好苦啊~ 0.0):
//安卓原生权限管理 适配小米等第三方
AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(Context
.APP_OPS_SERVICE);
int checkOp = appOpsManager.checkOp(AppOpsManager.OPSTR_FINE_LOCATION, Process.myUid
(), mContext
.getPackageName());
if (checkOp != AppOpsManager.MODE_IGNORED) {
return false;
}
三、补充
为了更好的用户体验,你应该对申请结果做处理,在用户拒绝权限时,应该友善地引导用户去理解这个权限的用处。
/**
* 申请权限结果返回处理
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[]
grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == UTILS_PERMISSION_REQUEST_CODE) {
boolean isAllGranted = true;
// 判断是否所有的权限都已经授予了
for (int grant : grantResults) {
if (grant != PackageManager.PERMISSION_GRANTED) {
isAllGranted = false;
break;
}
}
if (isAllGranted) {
// 如果所有的权限都授予了
//do some thing
} else {
// 弹出对话框告诉用户需要权限的原因, 并引导用户去应用权限管理中手动打开权限按钮
openAppDetails();
}
}
}
/**
* 打开 APP 的详情设置
*/
private void openAppDetails() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("应用需要 “录音” 权限,请到 “应用信息 -> 权限” 中授予!");
builder.setPositiveButton("去手动授权", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
}).setCancelable(false).show();
}
四、修正
工具类:
public class PermissionUtils {
public static final int UTILS_PERMISSION_REQUEST_CODE = 8069;//工具类权限请求码
/**
* 检查是否拥有指定的所有权限
*
* @param mContext
* @param normalPermissions
* @return
*/
public static boolean checkPermissionAllGranted(Context mContext, List<String>
normalPermissions) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String permission : normalPermissions) {
int checkSelf = ContextCompat.checkSelfPermission(mContext, permission);
if (checkSelf != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
/**
* 检查是否拥有指定的所有权限
*
* @param mContext
* @param normalPermissions
* @param appOpsPermissions 为了适配小米
* @return
*/
public static boolean checkPermissionAllGranted(Context mContext, List<String>
normalPermissions, List<String> appOpsPermissions) {
boolean checkSelfResult = true;
boolean checkOpResult = true;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String permission : normalPermissions) {
int checkSelf = ContextCompat.checkSelfPermission(mContext, permission);
if (checkSelf != PackageManager.PERMISSION_GRANTED) {
checkSelfResult = false;
}
}
}
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String appOpsPermission : appOpsPermissions) {
//安卓原生权限管理 适配小米等第三方
AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(Context
.APP_OPS_SERVICE);
int checkOp = appOpsManager.checkOp(appOpsPermission, Process.myUid(), mContext
.getPackageName());
switch (checkOp){
case AppOpsManager.MODE_ALLOWED:
Log.d("PermissionUtils", "权限:允许");
checkOpResult = true;
break;
case AppOpsManager.MODE_IGNORED:
Log.d("PermissionUtils", "权限:拒绝");
checkOpResult = false;
break;
case AppOpsManager.MODE_ERRORED:
Log.d("PermissionUtils", "权限:错误");
checkOpResult = false;
break;
case 4:
Log.d("PermissionUtils", "权限:询问");
checkOpResult = false;
break;
default:
checkOpResult = false;
break;
}
}
}
return (checkSelfResult && checkOpResult);
}
/**
* 一次请求多个权限, 如果其他有权限是已经授予的将会自动忽略掉
*
* @param activity
* @param normalPermissions
*/
public static void requestPermission(Activity activity, List<String> normalPermissions) {
int normalPermissionsNumber = normalPermissions.size();
ActivityCompat.requestPermissions(activity, normalPermissions.toArray(new
String[normalPermissionsNumber]), UTILS_PERMISSION_REQUEST_CODE);
}
}
使用
List<String> normalPermissions = new ArrayList<String>();//权限列表
//适配小米
List<String> appOpPermissions = new ArrayList<String>();//权限列表
normalPermissions.add(Manifest.permission.RECORD_AUDIO); //录音权限
normalPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION);//定位精确位置
//适配小米
appOpPermissions.clear();
appOpPermissions.add(AppOpsManager.OPSTR_RECORD_AUDIO);//录音权限
appOpPermissions.add(AppOpsManager.OPSTR_FINE_LOCATION);//定位精确位置
//检查权限
boolean isAllGranted = PermissionUtils.checkPermissionAllGranted(this, normalPermissions,
appOpPermissions);
if (isAllGranted) {//如果所有权限都有
//do some thing
} else {
//请求所有权限
PermissionUtils.requestPermission(AskForHelpActivity.this, normalPermissions);
}
网友评论