归纳整理自官方指南:
https://developer.android.com/training/permissions/requesting.html?hl=zh-cn#perm-request
简介
从Android6.0(API 23)开始, 在运行时请求权限, 而非在安装时.
简化了安装过程, 同时给予用户更大的自由去选择是否允许部分阻止另一部分权限获取.
权限分为两类:
- 正常权限
- 危险权限
在清单中需要全部列出, 如果是正常系统会自动授予, 如果是危险则需要用户明确同意才行.
PS. 如果忘了在清单中注册, 却在代码里请求权限的话, 会出现如下报错:
Unfortunately, package installer has stopped
检查权限
如果需要使用危险权限, 则每次使用前都需要检查是否具有该权限
(其实实际上应该是在开屏页就全部检查一遍?但是也存在用户开屏页同意然后再去setting中修改关闭权限, 再进行对应权限的操作时可能就会存在问题了)
使用支持库来进行检查, 这样就无需关心应用运行在哪个版本的系统上了
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);
返回:
PackageManager.PERMISSION_GRANTED
-> 0PackageManager.PERMISSION_DENIED
-> -1
如果返回了-1, 则需要进行权限的请求.
权限请求
Android提供了多种权限请求方式, 会弹出一个标准的Android对话框, 但无法对其自定义
解释为什么需要权限
在某些情况下, 应该对可能造成用户困惑的权限请求作出解释(比如摄影应用需要获取联系人权限)
请记住,您不需要通过解释来说服用户;如果您提供太多解释,用户可能发现应用令人失望并将其移除。
为了帮助发现是否处在这种情况, 有如下方法
shouldShowRequestPermissionRationale()
该方法返回true
或者false
- 如果之前请求过但是用户拒绝了, 返回true
- 如果之前请求过用户拒绝并点击了”Don’t ask again”, 或者设备规范就禁止获取该权限, 将会返回false
请求所需的权限
调用如下方法请求所需权限, 该方法异步运行, 会立即返回, 同时在用户做出决定以后再次返回(即两次回调)
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
系统显示的对话框项目是按照权限组进行分类的, 授予了该组中的一个以后其他的都会获得权限.
处理权限请求响应
即处理请求的回调, 回调方法是 onRequestPermissionsResult()
, 需要重写该方法并写入你自己所需的操作.
PS. 如果是在fragment里面请求了权限, 回调是在activity中响应的
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
注:您的应用仍需要明确请求其需要的每项权限,即使用户已向应用授予该权限组中的其他权限。此外,权限分组在将来的 Android 版本中可能会发生变化。您的代码不应依赖特定权限属于或不属于相同组这种假设。
- 如果用户取消了权限请求, 返回结果数组将会是空
- 如果用户拒绝了权限请求, 可能需要作出无法进行下一步操作的提示
- 如果用户设置不再提醒, 那么每次调用请求权限的时候都将被系统直接拒绝, 用户不会看到对话框交互. 所以这种情况下就需要利用
shouldShowRequestPermissionRationale()
方法来作出判断并进行提示了.