一、前言

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

CALENDAR

  • READ_CALENDAR
  • WRITE_CALENDAR

CAMERA

  • CAMERA

CONTACTS

  • READ_CONTACTS
  • WRITE_CONTACTS
  • GET_ACCOUNTS

LOCATION

  • ACCESS_FINE_LOCATION
  • ACCESS_COARSE_LOCATION

MICROPHONE

  • RECORD_AUDIO

PHONE

  • READ_PHONE_STATE
  • CALL_PHONE
  • READ_CALL_LOG
  • WRITE_CALL_LOG
  • ADD_VOICEMAIL
  • USE_SIP
  • PROCESS_OUTGOING_CALLS

SENSORS

  • BODY_SENSORS

SMS

  • SEND_SMS
  • RECEIVE_SMS
  • READ_SMS
  • RECEIVE_WAP_PUSH
  • RECEIVE_MMS

STORAGE

  • READ_EXTERNAL_STORAGE
  • WRITE_EXTERNAL_STORAGE

 



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. 只申请需要的权限,且只在需要的时候申请。