Android 动态权限申请

简介

权限列表

Android6.0以上把权限分为普通权限和危险权限,所以危险权限是需要动态申请,给予用户提示的。

看到上面的 permissions,会发现一个问题,危险权限都是一组一组的。

分组对权限机制的申请是有一定影响的。例如app运行在android 6.x的机器上,对于授权机制是这样的。如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对 READ_CONTACTS 已经授权了,当你的app申请 WRITE_CONTACTS 时,系统会直接授权通过。

此外,对于申请时的弹窗上面的文本说明也是对整个权限组的说明,而不是单个权限。

动态权限申请

1.首先要保证在AndroidManifest中写明需要的权限。

1
2
3
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.CAMERA"/>

2.权限申请示例 以获取定位权限为例。

  1. 点击按钮,检查并申请权限
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
    if (Build.VERSION.SDK_INT >23) {
    if (ContextCompat.checkSelfPermission(MainActivity.this,
    Manifest.permission.ACCESS_COARSE_LOCATION)
    == PackageManager.PERMISSION_GRANTED) {
    //授予权限
    getLoation();
    }else{
    //未获得权限
    requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}
    ,REQUEST_CODE_LOCATION);
    }
    }
    }
    });

如果有权限,执行获取位置逻辑,如果没权限,则进行请求权限。

  1. 权限申请结果回调
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == REQUEST_CODE_LOCATION){
    if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
    getLoation();
    } else{
    if (shouldShowRequestPermissionRationale( Manifest.permission.ACCESS_COARSE_LOCATION)){
    new AlertDialog.Builder(this)
    .setMessage("申请定位权限,才能为你推送更准确的信息")
    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
    //申请定位权限
    requestPermissions(MainActivity.this,
    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE_LOCATION);
    }
    }).show();
    }
    }
    return;
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

如果同意,执行获取位置逻辑,如果拒绝,重写 shouldShowRequestPermissionRationale 方法,返回 true,向用户弹窗给出一个获取权限的提示,点击后再次申请权限。

1
2
3
4
5
6
7
public boolean shouldShowRequestPermissionRationale(@NonNull String permission) {
if (permission.equals(Manifest.permission.ACCESS_COARSE_LOCATION) ) {
return true;
} else {
return super.shouldShowRequestPermissionRationale(permission);
}
}

重写shouldShowRequestPermissionRationale,在申请位置权限时,返回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
78
79
public class PermissionActivity extends AppCompatActivity implements View.OnClickListener {

private static final String TAG = "PermissionActivity";
public static final int REQUEST_CAMERA = 1;
private ConstraintLayout constraintLayout;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_permission);

initView();
}

private void initView() {
constraintLayout = findViewById(R.id.mainLayout);
findViewById(R.id.btn_camera).setOnClickListener(this);
findViewById(R.id.btn_contact).setOnClickListener(this);
}

@RequiresApi(api = Build.VERSION_CODES.M)
private boolean checkPermission(String permission) {
int i = checkSelfPermission(permission);
return i != PackageManager.PERMISSION_DENIED;
}

private void showSnackbar(String message) {
Snackbar.make(constraintLayout, message, Snackbar.LENGTH_SHORT).show();
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_camera:
showCamera();
break;
case R.id.btn_contact:
break;
}
}

private void showCamera() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkPermission(Manifest.permission.CAMERA)) {
showSnackbar("已授权,可以打开");
} else {
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
Snackbar.make(constraintLayout, "Camera permission is needed", Snackbar.LENGTH_SHORT)
.setAction("确定", new View.OnClickListener() {
@Override
public void onClick(View v) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA);
}
}).show();
} else {
requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA);
}
}
} else {
showSnackbar("可以直接打开");
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CAMERA:
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showSnackbar("已授权");
} else {
showSnackbar("拒绝授权");
}
}
break;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}

另外,在看一些 权限申请 的三方库的时候,发现了一件很有意思的事情。通常代码很难追踪到 Activity 的生命周期,一些库就新建一个 Fragment 在其生命周期的各个回调方法里去调用相应的方法。很棒。

参考文章

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×

keyboard_arrow_up 回到顶端