从 Android 6 (API < 23)开始,Android 系统提供动态权限申请机制,对于一些敏感的权限,决定权交还给了用户,不再是强制申请了。App 在使用危险权限的时,需用户授权才可以进一步操作。旧的权限申请方式是静态的,只要 App 在 AndroidManifest.xml 中注册了权限,安装APP后默认就获取了这些权限。这种授权方式安全性较低,容易被垃圾 App 窃取用户信息。
随着系统的升级,Google 也意识到静态权限申请的弊端,所以在 Android6.0 中,对权限进行了重新梳理,将权限分为普通权限和危险权限:
普通权限
- 不影响用户隐私的权限,AndroidManifest.xml 中注册即可获取
危险权限
- 可以访问用户隐私数据的权限,必须获取用户的同意才可获得授权。如下图:

在 Android 中应该尽量使用隔离式动态权限申请,什么是隔离式呢,就是动态申请权限的时候,用户没有授权时,屏蔽相关功能即可,而不是打开App不授权的话,直接退出App,不让用户使用,这种权限使用方式用户体验太差。常见于华为手机的各种自带App,不给权限,直接退出。
动态权限申请过程
检查权限
Activity 继承 AppCompatActivity,首先检查是否已经赋予权限,如果没有授权,可以使用 checkSelfPermission(@NonNull Context context, @NonNull String permission)方法,通过返回值来判断。具体代码如下:
1 | if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) |
申请权限
上个步骤中,没有授权的话,需要去申请动态权限,可以通过requestPermissions(final @NonNull Activity activity,final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode)来进行申请。需要定义一个静态变量作为requestCode。
1 | private static final int REQUEST_CALL_PHONE = 100; |
于是在手机界面上会弹出权限提示框,为系统样式,不可修改。拒绝或者同意都会走到接下来的流程。
处理结果
在onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)方法中处理接收到拒绝还是允许的结果消息。
1 | @Override |
如果用户选择同意,就可以调用拨打电话的按钮,同时这个对话框之后都不会出现了。
如果用户拒绝了,那就无法调用拨打电话的代码了。为了用户体验,可以弹出一个对话框,告知用户我需要这个权限,没有这个权限程序无法正常运行。
如果用户勾选了不再询问或者 禁止后不再询问,意味着用户永远地拒绝了相关的权限,同时这个对话框不会再弹出来了。为了挽救一下,我们可以弹框提示用户去设置里面手动开启权限。可以使用Android 提供的shouldShowRequestPermissionRationale(@NonNull Activity activity,@NonNull String permission)方法来判断用户是否选择了不再提示相关选项。
处理结果消息的代码,可以修改为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CALL_PHONE:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
callPhone();
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)) {
showTipDialog();
} else {
goToSetting();
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
以上就是动态权限申请的全部过程了。完整代码,见下面链接。