对于6.0以下的权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装,造成了我们想要使用某个app,就要默默忍受其一些不必要的权限(比如是个app都要访问通讯录、短信等)。而在6.0以后,我们可以直接安装,当app需要我们授予不恰当的权限的时候,我们可以予以拒绝(比如:单机的象棋对战,请求访问任何权限,我都是不同意的)。当然你也可以在设置界面对每个app的权限进行查看,以及对单个权限进行授权或者解除授权。
新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。
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 Permissions:
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
看到上面的dangerous permissions,会发现一个问题,好像危险权限都是一组一组的,恩,没错,的确是这样的,
那么有个问题:分组对我们的权限机制有什么影响吗?
的确是有影响的,如果app运行在Android 6.x的机器上,对于授权机制是这样的。如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。
不过需要注意的是,不要对权限组过多的依赖,尽可能对每个危险权限都进行正常流程的申请,因为在后期的版本中这个权限组可能会产生变化,就目前8.0,就已经做了这样的变化了。
在 Android 8.0 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用。
对于针对 Android 8.0 的应用,此行为已被纠正。系统只会授予应用明确请求的权限。然而,一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准。
例如,假设某个应用在其清单中列出 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE。应用请求 READ_EXTERNAL_STORAGE,并且用户授予了该权限。如果该应用针对的是 API 级别 24 或更低级别,系统还会同时授予 WRITE_EXTERNAL_STORAGE,因为该权限也属于同一 STORAGE 权限组并且也在清单中注册过。如果该应用针对的是 Android 8.0,则系统此时仅会授予 READ_EXTERNAL_STORAGE;不过,如果该应用后来又请求 WRITE_EXTERNAL_STORAGE,则系统会立即授予该权限,而不会提示用户。
所以不要对权限组过多的依赖,下面是我最近封装了一个权限申请:
1、检查权限是否已被授予;
checkSelfPermission(String permission)
2、没有则申请权限;
requestPermissions(@NonNull String[] permissions, int requestCode)
3、处理申请权限结果,成功和失败;
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults)
基本上就完事了,下面就是一些部分代码。
open class BasePermissionsActivity : RxAppCompatActivity(), PermissionsTransfer {
private val REQUEST_PERMISSIONS = 0x20
private var mPermissionPendingRunnable: Runnable? = null
/**
* 请求权限:
*
*/
override fun requestPermissions(permissions: Array<String>, pendingRunnable: Runnable?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkPermissions(permissions)) {
executePendingRunnable(pendingRunnable)
return
}
//Remind the pendingRunnable
mPermissionPendingRunnable = pendingRunnable
return
}
//否则直接执行
executePendingRunnable(pendingRunnable)
}
override fun onDestroy() {
super.onDestroy()
mPermissionPendingRunnable = null
}
override fun requestPermissions(permissions: Array<String>, pendingRunnable: () -> Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkPermissions(permissions)) {
pendingRunnable()
}
return
}
//否则直接执行
pendingRunnable()
}
private fun executePendingRunnable(action: Runnable?) = action?.run()
@TargetApi(Build.VERSION_CODES.M)
private fun checkPermissions(permissions: Array<String>): Boolean {
val needRequestPermissions = ArrayList<String>(1)
permissions.forEach {
if (checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED) {
needRequestPermissions.add(it)
}
}
if (needRequestPermissions.size > 0) {
val requestPermissions = arrayOfNulls<String>(needRequestPermissions.size)
needRequestPermissions.toArray(requestPermissions)
requestPermissions(requestPermissions, REQUEST_PERMISSIONS)
return false
}
// 如果已经具有本次所需的权限,则返回True
return true
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
REQUEST_PERMISSIONS -> {
handlePermissionsResult(permissions as Array<String>, grantResults)
}
else -> {
}
}
}
/**
* 处理权限请求结果
*/
private fun handlePermissionsResult(permissions: Array<String>, grantResults: IntArray) {
val requestPermissionLength = permissions.size
val requestFailurePermissionsList = ArrayList<String>(1)
for (index in 0 until requestPermissionLength) {
val permission = permissions[index]
val isPermissionGranted = grantResults[index] == PackageManager.PERMISSION_GRANTED
KLogUtil.e("RequestPermission:$permission granted:$isPermissionGranted")
if (!isPermissionGranted) {
requestFailurePermissionsList.add(permission)
}
}
if (requestFailurePermissionsList.size > 0) {
val requestFailurePermissions = arrayOfNulls<String>(requestFailurePermissionsList.size)
requestFailurePermissionsList.toArray(requestFailurePermissions)
handleRequestPermissionsFailure(requestFailurePermissions)
} else {
handleRequestPermissionSuccess(permissions)
}
}
private fun handleRequestPermissionSuccess(permissions: Array<String>) {
onRequestPermissionsSuccess(permissions)
executePendingRunnable(mPermissionPendingRunnable)
mPermissionPendingRunnable = null
}
private fun handleRequestPermissionsFailure(requestFailurePermissions: Array<String?>) {
onRequestPermissionsFailure(requestFailurePermissions)
mPermissionPendingRunnable = null
Build.VERSION_CODES.JELLY_BEAN
}
override fun onRequestPermissionsFailure(requestFailurePermissions: Array<String?>) {
}
override fun onRequestPermissionsSuccess(permissions: Array<String>) {
}
}
最近项目紧,好久没有更新了,把最近在项目中权限给总结一下,以前总是使用第三方库,不如直接自己封装,后面用起来方便一些。