Android 6.0之后的动态权限

原文地址:http://blog.magicer.xyz/2017/01/android-api-23-permission/

前言

在Android 6.0之前,开发Android应用程序的时,开发者需要使用什么权限只需要在AndroidManifest.xml文件中显示的声明即可。如下:

1
2
3
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

但是,在Android 6.0之后,Android对应用程序的权限进行了进一步的规范。分出来危险权限和一般权限,当我们需要危险权限的时候需要在运行时进行授权。这样做也有好处。对于一些应用用户的选择更多了。

权限分类

官方权限教程
当我们需要用到危险权限时,我们就需要动态的申请权限,那么危险权限有哪些呢?

危险权限

图片描述

一般权限

对于常规的权限我们只需要在清单文件中注册即可,比如网络权限。

动态注册权限

如果您的应用需要危险权限,则每次执行需要这一权限的操作时您都必须检查自己是否具有该权限。用户始终可以自由调用此权限,因此,即使应用昨天使用了相机,它不能假设自己今天仍具有该权限。

要检查您是否具有某项权限,请调用ContextCompat.checkSelfPermission() 方法。例如,以下代码段显示了如何检查 Activity 是否具有在日历中进行写入的权限:

1
2
3
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);

如果应用具有此权限,方法将返回 PackageManager.PERMISSION_GRANTED,并且应用可以继续操作。如果应用不具有此权限,方法将返回 PERMISSION_DENIED,且应用必须明确向用户要求权限。

以上是官方文档中关于检测权限的说明。
先来个小demo。看下怎么动态的请求权限,也可以看官方文档中的介绍。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private static final int PERMISSION_REQUEST_CODE = 1; //权限请求码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
//获取权限后的操作。读取文件
}else {
//请求权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_REQUEST_CODE);
}
}
/**
* 检测权限是否授权
* @return
*/
private boolean checkPermission(Context context, String permission) {
return PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(context,permission);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case PERMISSION_REQUEST_CODE:
if (grantResults.length >0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED){
//得到了授权
Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
}else {
//未授权
Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}

当用户点击了禁止按钮后,当我们下次还需要该权限怎么办? shouldShowRequestPermissionRationale()函数会在用户点击了禁止后返回true,我们可以在该方法返回true时在提示用户开启权限。
代码跟上面的差不多。可以简要看一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
private static final int PERMISSION_REQUEST_CODE = 1; //权限请求码
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button) findViewById(R.id.activity_main_storage_btn);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
storagePermission();
}
});
}
private void storagePermission() {
if (checkPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
//获取权限后的操作。读取文件
}else {
// //请求权限
// ActivityCompat.requestPermissions(this,
// new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
// PERMISSION_REQUEST_CODE);
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, "需要开启存储权限", Toast.LENGTH_SHORT).show();
showRequestPermissionDialog(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},PERMISSION_REQUEST_CODE);
}else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_REQUEST_CODE);
}
}
}
private void showRequestPermissionDialog(final String[] permissions, final int requestCode) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("使用该功能需要使用SD卡权限\n是否再次开启权限");
builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity.this,permissions,requestCode);
}
});
builder.setNegativeButton("否",null);
builder.setCancelable(true);
builder.show();
}
/**
* 检测权限是否授权
* @return
*/
private boolean checkPermission(Context context, String permission) {
return PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(context,permission);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case PERMISSION_REQUEST_CODE:
if (grantResults.length >0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED){
//得到了授权
Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
}else {
//未授权
Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}