android从第一版本开始就存在权限机制。为保护用户信息安全,每个APP在获取相应信息或完成特定功能时,都需要申请某种权限。例如,访问网络,获取联系人信息,拨打电话等等。而所有这些需要申请的权限,都需要在Mainfest中进行声明。
android6.0是权限批准方式的一个分水岭。
在6.0之前,系统会在安装APP时询问用户,是否批准APP所要申请的权限,如果批准,则APP可被安装并使用。否则,不被安装。好处是,APP申请的权限一目了然,不会有什么猫腻。缺点是,容易造成“店大欺客”。例如在达到一定用户量之后,APP升级时,在Mainfest中申请大量权限,不管有用没用。用户若放弃升级,则不能继续使用。决定升级,则需要为APP开放大量权限,埋下安全隐患。
在6.0之后,系统在安装APP时列出所有权限,由用户选择批准其中的哪些,拒绝其中哪些。但不论如何做选择,都不会影响APP的安装。只是由于部分权限被拒绝授权,相应功能不能得到使用罢了。
在6.0之后,系统还对权限进行了更进一步的分类。分为普通权限和危险权限。
普通权限,不需要用户刻意授权。只要APP申请,系统便会自动授权。例如申请访问网络,android.permission.ACCESS_NETWORK_STATE。
危险权限,则分为9组24权限。APP若申请,需要用户确认,系统才会授权。
需要注意的是,对于危险权限,若对某一组中的某一权限授权,同组其他权限也将被同时授权。
通常,执行某一未授权的功能,会造成异常。以使用系统相机为例。
在Manifest中申请权限
<uses-permission android:name="android.permission.CAMERA"/>
实现打开相机的函数
private void openCamera(){
Intent intent =new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivity(intent);
}
当点击按钮,触发打开相机函数时,APP会崩溃,并报异常,如下。
java.lang.SecurityException: Permission Denial: starting Intent { act=android.media.action.IMAGE_CAPTURE cmp=com.huawei.camera/.ThirdCamera } from ProcessRecord{fe5692 5608:0:com.breakloop.permissionruntimetest/u0a247} (pid=5608, uid=10247) with revoked permission android.permission.CAMERA
处理这种情况的有效办法是,运行时授权。即在运行时,判断相应权限是否被授权,若未授权,则提示申请。若在提示授权后,仍拒绝授权,则忽略后续操作。若已授权,则执行后续操作。
因此,我们需要完成三个步骤。
(1)询问是否已经获取权限。
调用方法ContextCompat.checkSelfPermission(Context, Permission)
若返回PackageManager.PERMISSION_GRANTED,则表示已经批准。
若返回PackageManager.PERMISSION_DENIED,则表示未授权。
(2)若未获取权限,则申请权限
调用方法ActivityCompat.requestPermissions(Context, Permissions, RequestCode)
其中,Permissions为需要申请的权限列表,为String类型。
RequestCode为整数类型,只是为了区分不同的申请,只要唯一不冲突即可。
(3)监听权限申请结果
重新onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)方法,以监听申请结果。
核心代码如下
@OnClick({R.id.btn_opencamera})
public void onClick(View view){
switch (view.getId()){
case R.id.btn_opencamera:
if(ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED){
openCamera();
}else {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},1);
}
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
openCamera();
}else {
Toast.makeText(this, "Camera Permission Denied", Toast.LENGTH_SHORT).show();
}
break;
}
}
仅当APP被卸载后,权限授权才失效。