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权限检查,看该权限是否已经授权。这个授权可以在设置中进行设置,默认是没有授权。
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
精品内容,独家发布
一、权限分类
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
精品内容,独家发布
相关文章推荐
- Android TextView 实现文字大小不同和文字颜色不同
- Android-Sqlite使用手册
- Android中的对话框
- Android WiFi调式工具WiFi ADB的使用
- Android_ListView
- Android Studio创建数据库表的一个问题
- Android中的soundpool小结
- (4.5.4)Android测试TestCase单元(Unit test)测试和instrumentationCase单元测试
- EditText点击事件——弹出单选框
- android 发送GET请求 服务端接收乱码的问题
- 认清Android框架 MVC,MVP和MVVM
- Android Task任务栈
- Android 多状态按钮ToggleButton
- Android-Tips(实用Android开发技巧)
- Android应用中使用百度地图API定位自己的位置(二)
- Android学习第七篇——ViewPager引导页
- Android GoogleMap suggestion AutoComplete (二)具体实现
- Bitmap的简单特效处理
- androidstudio多个module放在一个目录下
- Android Studio 高级配置