Android 6.0运行时权限小结

来源:互联网 发布:荷兰蒂尔堡大学 知乎 编辑:程序博客网 时间:2024/05/22 04:47

本文基于googlesamples-android-RuntimePermissions进行分析。

一、权限分类

Normal Permissions:普通权限,不需要授权管理

ACCESS_LOCATION_EXTRA_COMMANDSACCESS_NETWORK_STATEACCESS_NOTIFICATION_POLICYACCESS_WIFI_STATEBLUETOOTHBLUETOOTH_ADMINBROADCAST_STICKYCHANGE_NETWORK_STATECHANGE_WIFI_MULTICAST_STATECHANGE_WIFI_STATEDISABLE_KEYGUARDEXPAND_STATUS_BARGET_PACKAGE_SIZEINSTALL_SHORTCUTINTERNETKILL_BACKGROUND_PROCESSESMODIFY_AUDIO_SETTINGSNFCREAD_SYNC_SETTINGSREAD_SYNC_STATSRECEIVE_BOOT_COMPLETEDREORDER_TASKSREQUEST_INSTALL_PACKAGESSET_ALARMSET_TIME_ZONESET_WALLPAPERSET_WALLPAPER_HINTSTRANSMIT_IRUNINSTALL_SHORTCUTUSE_FINGERPRINTVIBRATEWAKE_LOCKWRITE_SYNC_SETTINGS

Dangerous Permission:危险权限,涉及用户隐身,需要授权管理

group:android.permission-group.CONTACTS  permission:android.permission.WRITE_CONTACTS  permission:android.permission.GET_ACCOUNTS  permission:android.permission.READ_CONTACTSgroup:android.permission-group.PHONE  permission:android.permission.READ_CALL_LOG  permission:android.permission.READ_PHONE_STATE  permission:android.permission.CALL_PHONE  permission:android.permission.WRITE_CALL_LOG  permission:android.permission.USE_SIP  permission:android.permission.PROCESS_OUTGOING_CALLS  permission:com.android.voicemail.permission.ADD_VOICEMAILgroup:android.permission-group.CALENDAR  permission:android.permission.READ_CALENDAR  permission:android.permission.WRITE_CALENDARgroup:android.permission-group.CAMERA  permission:android.permission.CAMERAgroup:android.permission-group.SENSORS  permission:android.permission.BODY_SENSORSgroup:android.permission-group.LOCATION  permission:android.permission.ACCESS_FINE_LOCATION  permission:android.permission.ACCESS_COARSE_LOCATIONgroup:android.permission-group.STORAGE  permission:android.permission.READ_EXTERNAL_STORAGE  permission:android.permission.WRITE_EXTERNAL_STORAGEgroup:android.permission-group.MICROPHONE  permission:android.permission.RECORD_AUDIOgroup:android.permission-group.SMS  permission:android.permission.READ_SMS  permission:android.permission.RECEIVE_WAP_PUSH  permission:android.permission.RECEIVE_MMS  permission:android.permission.RECEIVE_SMS  permission:android.permission.SEND_SMS  permission:android.permission.READ_CELL_BROADCASTS
  需要说明的是,系统的授权管理是以组为单位来授权的,请求某个组的某个权限,也相当于请求该组权限,如果用户同意授权,就相当于对整组权限都进行了授权,当请求该组其他权限的时候,就不需要请求授权了。

 二、权限使用与授权
  对应权限的使用,跟以前是一样的,唯一不同的就是增加了授权管理这一环节。

1、AndroidManifest中进行权限声明。

下面来看看android-RuntimePermissions中的AndroidManifest文件。

<!-- BEGIN_INCLUDE(manifest) --><!-- Note that all required permissions are declared here in the Android manifest. On Android M and above, use of these permissions is only requested at run time. --><uses-permission android:name="android.permission.CAMERA"/><!-- The following permissions are only requested if the device is on M or above. On older platforms these permissions are not requested and will not be available. --><uses-permission-sdk-m android:name="android.permission.READ_CONTACTS" /><uses-permission-sdk-m android:name="android.permission.WRITE_CONTACTS" /><!-- END_INCLUDE(manifest) -->
可以看到上面有两种声明形式,这个跟之前是有些不同的,uses-permission是普通的权限声明,uses-permission-sdk-m表示只有在Android M及其以上的设备上才声明该权限,在之前的版本是不用该权限,就相当于没有声明一样。
上面可以看到,声明了三种权限,其中READ_CONTACTS和WRITE_CONTACTS在android M及其以上版本才使用。它们都是危险权限。
所以在代码中,先需要进行系统版本判断,如果是低于Android M的系统,就不能使用READ_CONTACTS和WRITE_CONTACTS这两个权限。因为它只在android M及其以上版本才声明。

// BEGIN_INCLUDE(m_only_permission)if (Build.VERSION.SDK_INT < 23) {    /*    The contacts permissions have been declared in the AndroidManifest for Android M  and    above only. They are not available on older platforms, so we are hiding the button to    access the contacts database.    This shows how new runtime-only permissions can be added, that do not apply to older    platform versions. This can be useful for automated updates where additional    permissions might prompt the user on upgrade.     */    root.findViewById(R.id.button_contacts).setVisibility(View.GONE);}// END_INCLUDE(m_only_permission)
上面进行判断,如果系统版本低于23,就将READ_CONTACTS和WRITE_CONTACTS请求的按钮隐藏。

二、授权管理的过程
下面来看看授权管理的过程。
当我们需要使用某个权限的时候,例如我们要打开摄像头,这个时候,就需要首先进行CAMERA权限检查,看该权限是否已经授权。这个授权可以在设置中进行设置,默认是没有授权。
public void showCamera(View view) {    Log.i(TAG, "Show camera button pressed. Checking permission.");    // BEGIN_INCLUDE(camera_permission)    // Check if the Camera permission is already available.    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)            != PackageManager.PERMISSION_GRANTED) {        // Camera permission has not been granted.        requestCameraPermission();    } else {        // Camera permissions is already available, show the camera preview.        Log.i(TAG,                "CAMERA permission has already been granted. Displaying camera preview.");        showCameraPreview();    }    // END_INCLUDE(camera_permission)}
上面的核心代码就是上面的if判断语句。如果没有授权就会进行权限请求,执行requestCameraPermission()方法。

private void requestCameraPermission() {    Log.i(TAG, "CAMERA permission has NOT been granted. Requesting permission.");    // BEGIN_INCLUDE(camera_permission_request)    if (ActivityCompat.shouldShowRequestPermissionRationale(this,            Manifest.permission.CAMERA)) {        // Provide an additional rationale to the user if the permission was not granted        // and the user would benefit from additional context for the use of the permission.        // For example if the user has previously denied the permission.        Log.i(TAG,                "Displaying camera permission rationale to provide additional context.");        Snackbar.make(mLayout, R.string.permission_camera_rationale,                Snackbar.LENGTH_INDEFINITE)                .setAction(R.string.ok, new View.OnClickListener() {                    @Override                    public void onClick(View view) {                        ActivityCompat.requestPermissions(MainActivity.this,                                new String[]{Manifest.permission.CAMERA},                                REQUEST_CAMERA);                    }                })                .show();    } else {        // Camera permission has not been granted yet. Request it directly.        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},                REQUEST_CAMERA);    }    // END_INCLUDE(camera_permission_request)}
上面在权限请求之前,执行了ActivityCompat.shouldShowRequestPermissionRationale()方法,当第一次进行某个权限请求的时候,它返回为false,当再次请求该权限的时候,它返回true,目的就是可以给开发者一个接口,来说明为什么屡次请求使用该权限。可以看到在上面代码中,当再次请求的时候,它使用了一个Snackbar弹出一条消息进行说明,如果用户同意就进行请求该权限。说白了,就是为了提供一个比较好的交互效果,并且提供开发者向用户一个解释的机会。
当调用ActivityCompat.requestPermissions()的时候,就会有一个弹框,这个是系统弹出来的,用户需要进行选择是否同意授权,用户选择之后,就会回调onRequestPermissionsResult()方法,它会把用户的选择结果给带回来,所以我们需要实现ActivityCompat.OnRequestPermissionsResultCallback接口的该方法。

@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,        @NonNull int[] grantResults) {    if (requestCode == REQUEST_CAMERA) {        // BEGIN_INCLUDE(permission_result)        // Received permission result for camera permission.        Log.i(TAG, "Received response for Camera permission request.");        // Check if the only required permission has been granted        if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {            // Camera permission has been granted, preview can be displayed            Log.i(TAG, "CAMERA permission has now been granted. Showing preview.");            Snackbar.make(mLayout, R.string.permision_available_camera,                    Snackbar.LENGTH_SHORT).show();        } else {            Log.i(TAG, "CAMERA permission was NOT granted.");            Snackbar.make(mLayout, R.string.permissions_not_granted,                    Snackbar.LENGTH_SHORT).show();        }        // END_INCLUDE(permission_result)    } else if (requestCode == REQUEST_CONTACTS) {        Log.i(TAG, "Received response for contact permissions request.");        // We have requested multiple permissions for contacts, so all of them need to be        // checked.        if (PermissionUtil.verifyPermissions(grantResults)) {            // All required permissions have been granted, display contacts fragment.            Snackbar.make(mLayout, R.string.permision_available_contacts,                    Snackbar.LENGTH_SHORT)                    .show();        } else {            Log.i(TAG, "Contacts permissions were NOT granted.");            Snackbar.make(mLayout, R.string.permissions_not_granted,                    Snackbar.LENGTH_SHORT)                    .show();        }    } else {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);    }}
细心的人可能看到,在我们进行权限请求的时候,也就是执行ActivityCompat.requestPermissions()方法的时候,它的第三个参数是一个请求码,在上面onRequestPermissionsResult()方法的回调中,第一个参数就是将这个请求码给带回来了,第二个参数就是用户请求的权限,第三个参数就是用户请求的结果。可以看到返回的结果是一个数组,这个我们可以看看前面的请求函数ActivityCompat.requestPermissions(),它的第二个参数为我们要请求的权限,可以看到,它是一个数组,所以返回的请求结果也是一个数组,它对应的就是每个权限的请求结果。

public static boolean verifyPermissions(int[] grantResults) {    // At least one result must be checked.    if(grantResults.length < 1){        return false;    }    // Verify that each required permission has been granted, otherwise return false.    for (int result : grantResults) {        Log.i("PermissionUtil", "result" + result);        if (result != PackageManager.PERMISSION_GRANTED) {            return false;        }    }    return true;}
它是对返回结果数组的每个结果进行判断,只要有一个权限为拒绝,则就返回为false。

0 0
原创粉丝点击