您的位置:首页 > 移动开发 > Android开发

Android 6.0运行时权限小结

2016-04-17 19:04 483 查看
本文基于googlesamples-android-RuntimePermissions进行分析。
一、权限分类

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

ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
Dangerous Permission:危险权限,涉及用户隐身,需要授权管理

group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS

group: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_VOICEMAIL

group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
permission:android.permission.CAMERA

group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO

group: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接口的该方法。
@Override
public 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。


欢迎关注我的公众号:DroidMind
精品内容,独家发布
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: