一、前言
Android M 开始,App不会在安装的时候授予权限,而是在运行时一个一个的询问用户授予权限。
1. 运行时权限仅当我们设置targetSdkVersion >= 23才起作用,当然还要是M系统的手机。app在6.0之前的设备依然使用旧的权限系统。
2. 如果app的targetSdkVersion < 23,或者手机版本 < 6.0 ,那将被认为app没有用23新权限测试过,那将被继续使用旧有规则:用户在安装的时候不得不接受所有权限,安装后app就有了那些权限咯!
注意,此时用户依然可以取消已经同意的授权!用户取消授权时,android 6.0系统会警告,但这不妨碍用户取消授权。
当我们在targetSdkVersion 低于23的App调用一个需要权限的函数时,这个权限如果被用户取消授权了的话,不抛出异常。但是他将啥都不干,结果导致函数返回值是null或者0。
二、官网流程翻译
官网:https://developer.android.com/training/permissions/index.html
1. Declaring Permissions 声明权限
在AndroidManifest.xml中声明
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.snazzyapp">
<uses-permission android:name="android.permission.SEND_SMS"/>
<application ...>
...
</application>
</manifest>
权限分正常和危险两种,正常的权限和以前一样,只需要在Manifest.xml中声明即可,在App安装时,自动分配权限,且用户也不可以在设置中取消权限;危险权限需要运行时申请。
权限组,将危险权限分组,同一个组里的任何一个权限被授权了,其他权限也自动被授权。
下面是权限表格
Permission Group | Permissions |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2. Requesting Permissions at Run Time 运行时申请权限
(1) 检测是否已经授权
/**
* Determine whether <em>you</em> have been granted a particular permission.
*
* @param permission The name of the permission being checked.
*
* @return {@link PackageManager#PERMISSION_GRANTED} if you have the
* permission, or {@link PackageManager#PERMISSION_DENIED} if not.
*
* @see PackageManager#checkPermission(String, String)
* @see #checkCallingPermission(String)
*/
checkSelfPermission(String)
(2) 请求权限
shouldShowRequestPermissionRationale()
判断是否需要为权限申请向用户友好提示
返回true,上次申请权限,用户选择拒绝。
返回false
第一次申请,或上次申请权限,用户选择拒绝,并选择了“不在提醒”的选项;
设备的策略禁止当前应用获取这个权限的授权。
注意:第二次请求权限时,才会有“不在提醒”的选项,如果用户一直拒绝,并没有选择“不在提醒”的选项,下次请求权限时,会继续有“不在提醒”的选项。
显示权限说明:是根据你的应用中使用的权限分类来的:
1.用户容易知道应用需要获取的权限:如一个拍照应用,需要摄像头的权限,是很正常,不用提示。
2.一些用户感觉困惑的一些权限:如:分享图片,还需要获取位置的权限,这个需要提示用户:为什么需要这个权限。
处理 “不再提醒”
如果用户拒绝某授权。下一次弹框,用户会有一个“不再提醒”的选项的来防止app以后继续请求授权。
如果这个选项在拒绝授权前被用户勾选了。下次为这个权限请求requestPermissions时,对话框就不弹出来了,结果就是,app啥都不干。
这将是很差的用户体验,用户做了操作却得不到响应。这种情况需要好好处理一下。
final private int REQUEST_CODE_ASK_PERMISSIONS = 123;
private void insertDummyContactWrapper() {
int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
showMessageOKCancel("You need to allow access to Contacts",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermissions(new String[]
{Manifest.permission.WRITE_CONTACTS},
REQUEST_CODE_ASK_PERMISSIONS);
}
});
return;
}
requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
REQUEST_CODE_ASK_PERMISSIONS);
return;
}
insertDummyContact();
}
(3) 处理请求返回结果
@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
}
}
3. Permissions Best Practices 权限申请最佳实践
1. 如果不需要对数据有特别的控制权的话,可以采取用Intent呼起系统应用的方式来避免申请权限,比如Camera、contacts、phone call,都是可以直接调用系统app的。
注意打电话操作虽然是用的Intent方式,如果是这样的写法context.startActivity(new Intent("android.intent.action.CALL", Uri.parse(formatter.format(tel)))); 也要申请权限;如果是用的 android.intent.action.DIAL来调起的话,就不需要。
2. 只申请需要的权限,且只在需要的时候申请。