一、问题描述
在Android开发中,往往会用到许多诸如摄像头、录音等权限。但是,我们都知道,小米、魅族等定制系统,或者360等安全软件在程序请求打开相机、录音等操作时,会先弹出对话框提示用户是否允许程序执行这些操作,如果用户选择允许则接下来的操作一切正常,如果用户选择拒绝之后,程序后面的工作将无法正常允许,甚至崩溃。
那么如何判断用户是拒绝还是允许了该权限呢?
二、错误的判断方式
在我到网上搜索这个问题的过程中,搜到了很多如下的判断方式,然而这其实是无效的(),先贴出代码看一下:
boolean permission = (PackageManager.PERMISSION_GRANTED == getPackageManager()
.checkPermission("android.permission.CAMERA", getPackageName()));
if (permission) {
Toast.makeText(this, "有这个权限", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "没有这个权限", Toast.LENGTH_SHORT).show();
}
如上,这段代码其实只是判断了你的程序是否在manifest文件中声明了某权限,并无法判断用户是否拒绝了某权限。
三、问题研究
当我们打开系统的应用权限管理或者安全软件的权限管理时,可以看到程序申请的权限列表,但是一些敏感权限都是有3种状态的,即“允许”、“提醒”、“禁用”。所以我们需要的不是判断权限是否在manifest文件中声明了没有,而是判断程序的权限状态到底是允许还是禁用。
然而,只有在安卓 6.0 之上才有这样的方法可以判断这个状态。
四、正确的解决方式
1.动态权限申请(Android 6.0 以上)
在 onCreate() 方法中调用权限检查,如果未拥有权限则动态申请权限
private void checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String[] permissions = new String[]{Manifest.permission.CAMERA};
int i = ContextCompat.checkSelfPermission(this, permissions[0]);
if (i != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, permissions, 200);
return;
}
}
}
还需要添加一个回调方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
grantResults) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && requestCode == 200) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initFragment();
} else {
Toast.makeText(this, "请在设置中打开权限后继续", Toast.LENGTH_SHORT).show();
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, 200);
}
}
}
2.使用 try-catch 这种暴力的解决方法吧
将相应代码 try-catch 起来,然后在catch块中提示用户打开相应权限。
try {
mCamera = Camera.open(0); // 任意可能被拒绝权限程序崩溃的代码
} catch (RuntimeException e) {
e.printStackTrace();
Toast.makeText(getActivity(), "请打开xx权限", Toast.LENGTH_LONG).show();
}
如果是发送短信等权限,则可以通过判断短信是否发送成功判断