Android 6.0 (API 23) 之前应用的权限在安装时全部授予,运行时应用不再需要询问用户。在 Android 6.0 或更高版本对权限进行了分类,对某些涉及到用户隐私的权限可在运行时根据用户的需要动态授予。这样就不需要在安装时被强迫同意某些权限。
应用的targetSDKVersion < 23时,权限检查仍是早期的形式(仅在安装时赋予权限,使用时将不被提醒);
应用的targetSDKVersion ≥ 23时,则将使用新的运行时权限规则。
新的权限机制更好的保护了用户的隐私,Google将权限分为三类:
- Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;
- Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等;
- Special Permissions,
SYSTEM_ALERT_WINDOW
和WRITE_SETTINGS
这两个权限比较特殊,不能通过代码申请方式获取,必须得用户打开软件设置页手动打开,才能授权。
1. 权限组
权限组 | 权限 |
---|---|
CALENDA |
READ_CALENDAR WRITE_CALENDAR |
CAMERA |
CAMERA |
CONTACTS |
READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS |
LOCATION |
ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION |
MICROPHONE |
RECORD_AUDIO |
PHONE |
READ_PHONE_STATE READ_PHONE_NUMBERS CALL_PHONE ANSWER_PHONE_CALLS (must request at runtime) READ_CALL_LOG WRITE_CALL_LOG ADD_VOICEMAIL USE_SIP PROCESS_OUTGOING_CALLS ANSWER_PHONE_CALLS |
SENSORS |
BODY_SENSORS |
SMS |
SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS |
STORAGE |
READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE |
2. 权限申请
1)声明权限
在 AndroidManifest.xml 中声明所需权限:
...
//电话
//拍照
//sd卡
...
2)检查权限
方法:
// 检查权限
ContextCompat.checkSelfPermission(Context context, String permission)
返回值PackageManager
常量有两种情况:PackageManager.PERMISSION_GRANTED
(有权限)、PackageManager.PERMISSION_DENIED
(无权限)
示例:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int permission = ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.CALL_PHONE);
if (permission == PackageManager.PERMISSION_GRANTED) {
//表示有权限
} else {
//表示无权限
}
}
当应用需要用到危险权限时,在执行权限相关代码前,使用该方法判断是否拥有指定的权限。有权限,则继续执行设计需要权限的代码;无权限,则向用户请求授予权限。
3)解释权限
方法:
// 解释权限
ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission)
示例:
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)) {
//拒绝权限
} else {
//申请对应的权限
}
判断是否有必要向用户解释为什么要这项权限。如果应用第一次请求过此权限,但是被用户拒绝了,则之后调用该方法将返回 true,此时就有必要向用户详细说明需要此权限的原因。如果用户勾选了权限请求对话框的 “不再询问”,则此方法返回 false。如果设备规范禁止应用拥有该权限,此方法也返回 false。
4)请求权限
方法:
// 请求权限
ActivityCompat.requestPermissions(Activity activity, String[] permissions, int requestCode)
示例:
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 100);
当检测到应用没有指定的权限时,调用此方法向用户请求权限。调用此方法将弹出权限请求对话框询问用户 “允许” 或 “拒绝” 指定的权限。
5)处理结果
方法:
//处理权限请求结果
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
// ...
}
示例:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 100) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//授权
} else {
//拒绝
}
}
}
requestCode
请求权限时传入的请求码,用于区别是哪一次请求的;
permissions
所请求的所有权限的数组;
grantResults
权限授予结果,和 permissions 数组参数中的权限一一对应,元素值为两种情况:
授予: PackageManager.PERMISSION_GRANTED
,拒绝:PackageManager.PERMISSION_DENIED
3. 代码案例
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE = 100;
private Button btn_record;
private String[] permit = new String[] {
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CALL_PHONE
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_record = (Button) findViewById(R.id.btn_record);
btn_record.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
List mPermissionList = new ArrayList<>();
for(String permission : permit) {
if(ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {//权限判断
permissionLists.add(permission);
}
}
if(!permissionLists.isEmpty()) {
ActivityCompat.requestPermissions(this, permissionLists.toArray(new String[permissionLists.size()]), REQUEST_CODE);
} else { //表示全都授权了
callPhone();
}
} else {
callPhone();
}
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE) {
if(grantResults.length > 0) {
//存放没授权的权限
List deniedPermissions = new ArrayList<>();
for(int i = 0; i < grantResults.length; i++) {
int grantResult = grantResults[i];
String permission = permissions[i];
if(grantResult != PackageManager.PERMISSION_GRANTED) {
deniedPermissions.add(permission);
}
}
if(deniedPermissions.isEmpty()) {
//都授权了
callPhone();
} else { //没有授权
Toast.makeText(MainActivity.this, "被拒绝的权限:" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
}
}
}
}
public void callPhone() {
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + "10086");
intent.setData(data);
startActivity(intent);
}
}