Android6.0运行时权限问题

2016-10-27  本文已影响93人  chrnie

前言

在 Android 6.0 之后的系统,除了要在 AndroidManifest.xml 文件中声明需要使用的权限,部分危险权限还需要在运行程序的过程中动态向用户申请。

在 AndroidManifest.xml 中申请权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.app.myapp" >
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    ...
</manifest>

危险权限列表

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

注意事项

  1. 危险权限有分组,在申请分组中的其中一个权限后,可以获得该分组中所有权限的使用权。
  2. 一次可以申请多个不同分组的权限,用户会进行多次授权,假若是同一分组的不同权限,因为如上原因,系统只对同一分组中的第一个权限进行一次用户授权询问。
  3. 假若用户已经同意该权限,再次申请会继续弹出对话框让用户选择,且假若用户拒绝会导致 Activity 摧毁再恢复,使得在 Fragment 中申请的权限没有系统回调。所以最好在申请前进行判断,以防万一。

运行时权限获取

使用 Activity

Activity#requestPermissions() 方法要求 min API level >= 23 才能使用,因为这是 Android M 才推出的需求,所以可以使用 support-v4 包中的 ActivityCompat#requestPermissions() 方法替代以做到向下兼容。

代码示例:

public static final int REQEST_CODE = 0;
public void example(){
    if(Build.VERSION.SDK_INT >= 23){
        int checkPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.XXX);
        if(checkPermission != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(context,new String[]{Manifest.permission.XXX},REQEST_CODE);
            return;
        }else{
            //do something
        }
    }else{
        // do something
    }
}

使用 Fragment

如果使用的是 support-v4 包中的 Fragment,可以直接使用 requestPermissions() 申请权限,否则同上。在这里推荐使用 support 包中的 Fragment 而不使用 SDK 中的,因为 support 包中的 Fragment 会比 SDK 中的功能更多,而且可以自由更新不受系统版本影响。

用户响应后的系统回调

系统会回调 onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 方法。

  1. requestCode 为申请时传递的值
  2. permissions 为申请的权限
  3. grantResults 为对应权限的获取结果,permissions[i] 对应 grantResults[i]

示例代码:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
    switch(requestCode){
        case REQEST_CODE:{
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                // Permission Granted
            }else{
                // Permission Denied
            }
            break;
        }
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

需要注意的是,onRequestPermissionsResult() 方法回在 Activity 恢复前调用,所以不可以在该方法中 commit FragmentTransaction,需要使用 commitAllowingStateLoss 替代。

上一篇下一篇

猜你喜欢

热点阅读