前言
Android6.0代号棉花糖。尽管是在15年I/O大会上Google被正式发布的了。但是看看大多数人的项目中大家的 targetSdkVersion 是不是还都用的22。大家都认为6.0+的市场占有率还没那么高。那么就请看谷歌2017年9月份公布的版本分布图。
从数据来看确实没那么高O(∩_∩)O。6.0+的市场占有率仅为50% ̄□ ̄||。只因安卓用户的基数太大了吧。延伸至各种人群。虽然说占比才一半但时基数大总的用户数量还是蛮多的。这两天刚做完6.0权限的适配。那么请说一下自己测试的时候踩的坑吧(*╹▽╹*)
权限管理系统的变化
在Android6.0(M)之前,在用户安装应用的时候会产生一个权限列表,只有用户允许这些权限后,应用才可以正常的安装,这就会产生一个问题,这些权限对用户是不具有感知性的,也就是说用户都不知道你要这些权限干什么,我明明装的是一个阅读类型的应用,你却要我拨打电话的权限,你想干嘛呢?当然绝大部分的开发者是善意的,但也避免不了一些特殊人群利用这些“漏洞”做一些不好的事情。
而在Android6.0(M)之后,用户是可以不管权限直接安装应用的,当应用需要调用某些权限的时候,会给予用户一个通知与说明,我要这些权限干什么,这样下来可以让用户有更加清醒的权限分配意识,也在一定程度上更加人性化的保护了用户的隐私,避免了“权限一刀切”。
权限的分组
在Android6.0(M)之后,对权限进行了分类,大致有这三种:
普通权限:也就是正常权限,是对手机的一些正常操作,对用户的隐私没有太大影响的权限,比如手机的震动,网络访问,蓝牙等权限,这些权限会在应用被安装的时候默认授予,用户不能拒绝,也不能取消。
普通权限列表:
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 INTERNET KILL_BACKGROUND_PROCESSES MODIFY_AUDIO_SETTINGS NFC READ_SYNC_SETTINGS READ_SYNC_STATS RECEIVE_BOOT_COMPLETED REORDER_TASKS REQUEST_INSTALL_PACKAGES SET_TIME_ZONE SET_WALLPAPER SET_WALLPAPER_HINTS TRANSMIT_IR USE_FINGERPRINT VIBRATE WAKE_LOCK WRITE_SYNC_SETTINGS SET_ALARM INSTALL_SHORTCUT UNINSTALL_SHORTCUT
对于上面这些普通权限 在Android6.0以前我们只需要在清单文件中声明该权限即可。
危险权限:其实就是运行中需要处理的权限,也是我们最需要注意的权限,这些权限会关系到用户的隐私或影响到其他应用的运行,这些危险权限,谷歌还做了一个权限组,以分组的形式来呈现:
由于运行权限机制的出现,我们需要对新开发的应用去做适配。
当你的应用targetSdkVersion小于23的时候,当应用用于6.0以上的系统时候,它也会默认采用以前的权限管理机制。当你的targetSdkVersion大于等于23的时候且在Andorid6.0(M)系统上,它才会采用新的这套权限管理机制。
所以如果你想逃开这个“麻烦”,只要把targetSdkVersion的版本设置为低于23就可以了,不过不建议采用这种方案,该来的总是要来的,随着国产手机ROM的更新,比如小米,华为等也开始有部分机型进行了系统升级,所以这是种趋势。
说了这么多,那么来看下怎么进行Android6.0(M)的权限管理适配吧,其实很简单,只需要记住下面几个API方法就可以:(API23之后提供)
int checkSelfPermission(String permission) 用来检测应用是否已经具有权限void requestPermissions(String[] permissions, int requestCode) 进行请求单个或多个权限void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 请求权限结果回调
checkSelfPermission(String permission) 方法返回值有两个:
requestPermissions(String[] permissions, int requestCode)
参数一:要请求的权限组 权限2请求码
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)请求的回调。
参数3对应 对应permissions的权限请求结果(PERMISSION_GRANTED或者PERMISSION_DENIED)
看完关键的三个方法接下来上我的油条:
object MQPermissionUtil { private var mRequestCode = -1 private val isOverMarshmallow: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M private var mOnPermissionListener: OnPermissionListener? = null fun requestPermissions(activity: Activity, requestCode: Int, permissions: Array<String>, isCancelFinish: Boolean, onPermissionGrantedListener: OnPermissionGrantedListener) { requestPermissionsResult(activity, requestCode, permissions, object : OnPermissionListener { override fun onPermissionGranted() { onPermissionGrantedListener.onPermissionGranted() } override fun onPermissionDenied() { if (isCancelFinish) { showTipsDialogWel(activity) } else { showTipsDialog(activity) } } }) } private fun requestPermissionsResult(activity: Activity, requestCode: Int, permissions: Array<String>, callback: OnPermissionListener) { mOnPermissionListener = callback if (checkPermissions(activity, *permissions)) { if (mOnPermissionListener != null) mOnPermissionListener!!.onPermissionGranted() } else { val deniedPermissions = getDeniedPermissions(activity, *permissions) if (deniedPermissions.isNotEmpty()) { mRequestCode = requestCode ActivityCompat.requestPermissions(activity, deniedPermissions .toTypedArray(), requestCode) } } } fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { if (requestCode == mRequestCode) { if (verifyPermissions(grantResults)) { if (mOnPermissionListener != null) mOnPermissionListener!!.onPermissionGranted() } else { if (mOnPermissionListener != null) mOnPermissionListener!!.onPermissionDenied() } } } private fun startAppSettings(context: Context) { val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) intent.data = Uri.parse("package:" + context.packageName) context.startActivity(intent) } private fun verifyPermissions(grantResults: IntArray): Boolean { if (grantResults.isEmpty()) return false // 循环判断每个权限是否被拒绝 for (grantResult in grantResults) { if (grantResult != PackageManager.PERMISSION_GRANTED) { return false } } return true } private fun getDeniedPermissions(context: Context, vararg permissions: String): List<String> { val deniedPermissions = ArrayList<String>() for (permission in permissions) { if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED) { deniedPermissions.add(permission) } } return deniedPermissions } private fun checkPermissions(context: Context, vararg permissions: String): Boolean { if (isOverMarshmallow) { for (permission in permissions) { if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED) { return false } } } return true } fun showTipsDialog(activity: Activity) { AlertDialog.Builder(activity) .setTitle("提示信息") .setMessage("当前应用缺少必要权限,無法正常使用,请单击【确定】按钮前往设置中心进行权限授权。") .setNegativeButton("取消", null) .setPositiveButton("确定") { _, _ -> activity.finish() startAppSettings(activity) }.show() } fun showTipsDialogWel(activity: Activity) { AlertDialog.Builder(activity) .setTitle("提示信息") .setMessage("当前应用缺少必要权限,無法正常使用,请单击【确定】按钮前往设置中心进行权限授权。") .setNegativeButton("取消") { _, _ -> activity.finish() } .setPositiveButton("确定") { _, _ -> activity.finish() startAppSettings(activity) }.show() } interface OnPermissionGrantedListener { fun onPermissionGranted() } interface OnPermissionListener { fun onPermissionGranted() fun onPermissionDenied() } }
写的不好。大家自行修改吧。
Activity中的使用在onCreate中一开始调用一下代码:
MangoPermissionUtil.requestPermissions(this@IndexActivity, Constant.PERMISSION_OPERATION_CODE_SCAN, arrayOf(Manifest.permission.CAMERA), false, object : MangoPermissionUtil.OnPermissionGrantedListener { override fun onPermissionGranted() { //在这表示用户同意了权限申请。 //假如用户拒绝了权限申请在这儿我是没让他进入到应用中的效果如下 } })
只要有任何一个权限用户没通过都会弹出这个Dialog。直到用户全部授权。。。。
点击取消退出应用。确定按钮去到设置界面为应用授权。。。。
下面是应用启动的场景(很舒服2333)
还有个剧TM恶心的问题这些所有的逻辑在除了小米6.xxx的设备上跑是没问题的。必须全部授权才能进入应用。但是小米6.xxx的设备上当我第一次拒绝了权限申请之后。第二次进入应用判断权限的时候它竟然在checkPermisssion的方法中给我返回了PERMISSION_GRANTED这就比较尴尬了。这样我是可以进入掉权限请求成功的回调。但是我进去之后确实没权限啊。对应权限相关的操作一样不能执行。。。不得不说小米的6.xxx设备是真的坑。。。。
还有一点油条用的时候还要在当前申请的Activity中调用一下来执行到油条中自定义的回调
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { MangoPermissionUtil.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults) }
最后
对于一些比较特别的权限,比如文件的读写权限,一般在我们第一次开启APP的时候就要去获取了,假设我们一开始没有获取到这个权限,那么如果我的首页有轮播广告图,这个广告图是网络获取的,做了三级缓存,这样就会到导致磁盘缓存无法写入。这边提供一个解决方法,就是在你引导APP启动的时候,就引导用户去获取权限,当用户拒绝的时候,应该给出弹出框并跳转对应的应用权限管理界面(需要对不同机型进行设置)。
可以参考微信的做法:
启动app,在闪屏页的时候向用户提出权限的申请
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对小牛知识库的支持。
本文向大家介绍详解适配iOS10 的相关权限设置,包括了详解适配iOS10 的相关权限设置的使用技巧和注意事项,需要的朋友参考一下 在最新版本的iOS10系统中,如果你的项目中访问了隐私数据,比如:相机、相册、录音、定位、联系人等等。涉及到权限问题。 解决办法(fix method): 在info.plist —Source Code中添加 UsageDescription相关的key, 描述字符
本文向大家介绍详解Android6.0运行时权限管理,包括了详解Android6.0运行时权限管理的使用技巧和注意事项,需要的朋友参考一下 自从Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有的权限而导致的无法安装的事情,也不会再不征求用户授权的情况下,就可以任意的访问用户
本文向大家介绍android6.0权限动态申请框架permissiondispatcher的方法,包括了android6.0权限动态申请框架permissiondispatcher的方法的使用技巧和注意事项,需要的朋友参考一下 1,添加依赖 在project的build.gradle文件中添加 在module的build.gradle中添加 2,添加注解 注释说明 RuntimePermissio
本文向大家介绍关于linux权限s权限和t权限详解,包括了关于linux权限s权限和t权限详解的使用技巧和注意事项,需要的朋友参考一下 常用权限 linux系统内有档案有三种身份 u:拥有者 g:群组 o:其他人 这些身份对于文档常用的有下面权限: r:读权限,用户可以读取文档的内容,如用cat,more查看 w:写权限,用户可以编辑文档 x:该目录具有可以被系统执行的权限 其他权限 除了读
权限适配 适配Android7.0权限,需要做以下设置: 在您自己工程的AndroidManifest.xml中添加以下代码。 <provider android:name="android.support.v4.content.FileProvider" android:authorities="${packageName}.fileProvider"
本文向大家介绍Android6.0动态申请权限所遇到的问题小结,包括了Android6.0动态申请权限所遇到的问题小结的使用技巧和注意事项,需要的朋友参考一下 白天在做SDK23版本的适配,遇到了不少坑,现在抽空记下来,以此为戒。 首先要知道哪些坑,就得先了解一些定义和基本使用方式。 那么先介绍一下动态申请的权限分组情况。 下面的权限组是由谷歌官方定义的,目的是在申请权限时,只要用户允许同一权限组