谈谈Android 6.0 的动态权限管理
Android适配系列:
Android 6.0 的动态权限管理
Android 7.0脱坑指南
Android 8.0适配指北
Android 9.0 适配指南
1.前言
大家都知道Android 6.0的新特性之一就是应用权限的管理。也就是说凡是涉及用户隐私的权限,用户可以自己去设置管理了。然而在6.0以前,我们安装一款APP是默认同意此APP所需的所有权限(比如定位、访问通讯录),不同意就不能安装。当然,国内的一些手机厂商基于Android定制的系统中,可以实现在6.0以前关闭指定的权限。如下图:
2.危险权限列表(Dangerous Permission)
Dangerous Permission一般都是涉及用户隐私的权限。
从上面的图片中可以看到,摄像头、电话、定位等等都是我们平常开发中常用的权限。
3.可以在6.0不适配权限管理吗?
答案是可以,但是不推荐。
首先说怎么不适配,那就是设置targetSdkVersion小于23(Android 6.0系统默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限,所以如果您APP设置的targetSdkVersion低于23,在运行时也不会崩溃。)
有人一看这不是挺好的嘛,解决问题。那么我想告诉你,首先这不是长久之计,早晚都要面对的。你不可能永远targetSdkVersion低于23。其次,它是有一个前提,那就是用户自己不去操作权限。要知道如果用户是6.0以上的手机或是国内部分6.0以前的手机,他可以自己在设置中关闭权限,那么到时APP因为没有权限获取数据异常,导致空指针的异常时,APP就会崩溃。
4.怎么适配
首先Android Studio:
在build.gradle中声明targetSdkVersion为23及以上。
Eclipse:
在AndroidManifest.xml中声明targetSdkVersion为23及以上。
这里引用高德定位Demo的CheckPermissionsActivity类,代码如下:
/*** 继承了Activity,实现Android6.0的运行时权限检测* 需要进行运行时权限检测的Activity可以继承这个类* * @创建时间:2016年5月27日 下午3:01:31 * @项目名称: AMapLocationDemo* @author hongming.wang* @文件名称:PermissionsChecker.java* @类型名称:PermissionsChecker* @since 2.5.0*/
public class CheckPermissionsActivity extends Activity {/*** 需要进行检测的权限数组*/protected String[] needPermissions = {Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.READ_PHONE_STATE};private static final int PERMISSON_REQUESTCODE = 0;/*** 判断是否需要检测,防止不停的弹框*/private boolean isNeedCheck = true;@Overrideprotected void onResume() {super.onResume();if (Build.VERSION.SDK_INT >= 23&& getApplicationInfo().targetSdkVersion >= 23) {if (isNeedCheck) {checkPermissions(needPermissions);}}}/*** * @param permissions* @since 2.5.0* requestPermissions方法是请求某一权限,*/private void checkPermissions(String... permissions) {try {if (Build.VERSION.SDK_INT >= 23&& getApplicationInfo().targetSdkVersion >= 23) {List<String> needRequestPermissonList = findDeniedPermissions(permissions);if (null != needRequestPermissonList&& needRequestPermissonList.size() > 0) {String[] array = needRequestPermissonList.toArray(new String[needRequestPermissonList.size()]);Method method = getClass().getMethod("requestPermissions", new Class[]{String[].class,int.class});method.invoke(this, array, PERMISSON_REQUESTCODE);}}} catch (Throwable e) {}}/*** 获取权限集中需要申请权限的列表* * @param permissions* @return* @since 2.5.0* checkSelfPermission方法是在用来判断是否app已经获取到某一个权限* shouldShowRequestPermissionRationale方法用来判断是否* 显示申请权限对话框,如果同意了或者不在询问则返回false*/private List<String> findDeniedPermissions(String[] permissions) {List<String> needRequestPermissonList = new ArrayList<String>();if (Build.VERSION.SDK_INT >= 23&& getApplicationInfo().targetSdkVersion >= 23){try {for (String perm : permissions) {Method checkSelfMethod = getClass().getMethod("checkSelfPermission", String.class);Method shouldShowRequestPermissionRationaleMethod = getClass().getMethod("shouldShowRequestPermissionRationale",String.class);if ((Integer)checkSelfMethod.invoke(this, perm) != PackageManager.PERMISSION_GRANTED|| (Boolean)shouldShowRequestPermissionRationaleMethod.invoke(this, perm)) {needRequestPermissonList.add(perm);}}} catch (Throwable e) {}}return needRequestPermissonList;}/*** 检测是否所有的权限都已经授权* @param grantResults* @return* @since 2.5.0**/private boolean verifyPermissions(int[] grantResults) {for (int result : grantResults) {if (result != PackageManager.PERMISSION_GRANTED) {return false;}}return true;}/*** 申请权限结果的回调方法*/@TargetApi(23)public void onRequestPermissionsResult(int requestCode,String[] permissions, int[] paramArrayOfInt) {if (requestCode == PERMISSON_REQUESTCODE) {if (!verifyPermissions(paramArrayOfInt)) {showMissingPermissionDialog();isNeedCheck = false;}}}/*** 显示提示信息* * @since 2.5.0**/private void showMissingPermissionDialog() {AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle(R.string.notifyTitle);builder.setMessage(R.string.notifyMsg);// 拒绝, 退出应用builder.setNegativeButton(R.string.cancel,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {finish();}});builder.setPositiveButton(R.string.setting,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {startAppSettings();}});builder.setCancelable(false);builder.show();}/*** 启动应用的设置* * @since 2.5.0**/private void startAppSettings() {Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);intent.setData(Uri.parse("package:" + getPackageName()));startActivity(intent);}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if(keyCode == KeyEvent.KEYCODE_BACK){this.finish();return true;}return super.onKeyDown(keyCode, event);}}
我在上面的类中,自己加入了一些注释,大家仔细看就可以明白了。
补充:小米手机在动态权限这里还需要一些兼容,我们需要注意一下。当然对于国内部分6.0以前手机,只能在需要权限去去捕获异常来处理了。
当然不止上面一种实现方法,github上有许多大神开源的封装库,可以很方便的实现权限适配。我推荐两个库,大家根据需求选择:
1. PermissionsDispatcher
2. 鸿洋大神的MPermissions
5.参考
1. Android M 新的运行时权限开发者需要知道的一切
2. 高德地图定位API
谈谈Android 6.0 的动态权限管理相关推荐
- 【Android 应用开发】动态权限管理示例 ( 使用原生代码实现 | 申请权限 | 判定权限申请结果 | 判定 “ 不再询问 “ 情况 )
文章目录 一.申请权限 二.判定权限申请结果 三.判定 " 不再询问 " 情况 四.完整代码示例 1.权限管理代码 2.主界面代码 3.执行结果 五.博客资源 一.申请权限 首先 ...
- Android 6.0运行时权限管理
运行时权限管理 定义: 之前我们的App需要权限,只需在manifest中申明,用户安装后,一切申明的权限都可使用. 但是Android 6.0以后Android M把权限管理做了加强处理,除了需要在 ...
- 谈谈Android 6.0运行时权限理解
前言 谷歌在2015年8月份时候,发布了Android 6.0版本,代号叫做"棉花糖"(Marshmallow ),其中的很大的一部分变化,是在用户权限授权上,或许是感觉之前默认授 ...
- Android动态权限管理模型(4.3-6.0)
Google从4.3开始就试图引入AppOpsManager动态权限管理模型,但是,由于感觉技术不太成熟,在Release版本中,这个功能都是被隐藏掉的,所以官方Rom一直没有动态权限管理机制.直到A ...
- Android 8.0 运行时权限策略变化和适配方案
Android8.0也就是Android O即将要发布了,有很多新特性,目前我们可以通过AndroidStudio3.0 Canary版本下载Android O最新的系统映像的Developer Pr ...
- Android 系统(80)---Android 8.0 7.0 6.0 动态权限管理
Android 8.0 7.0 6.0 动态权限管理 1.Android6.0之后运行时权限策略变化 从Android6.0(API23)开始,对系统权限做了很大的改变,在之前用户安装app前,只是把 ...
- Android 6.0: 动态权限管理的解决方案
Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用户体验, 同时也为程序员带来新的负担. 动态权限管理就是这样, 一方面让用户更加容易的控制自己的隐私, 一方面需要重新适配应 ...
- Andorid6.0 动态权限管理
Github地址 我的博客地址 前言:动态权限管理是Android6.0(B>uild.VERSION_CODES.M =Api23)推出的,提醒用户当前APP所需>要的权限,防止滥用.这 ...
- Android 9.0模拟器root权限获取
Android 9.0在获取权限时报如下错误 remount of the / superblock failed: Permission denied remount failed 解决方法为: 1 ...
最新文章
- 矩形内接任意多边形抠图(可以羽化边缘)
- mysql数据库utf-8编码
- 剧透LiveVideoStackCon 2020:除了干货,还有更多优惠的年度通票
- Linux恢复win分区,找到了linux分区顺序错乱修复方法
- 移动端设置html的字体尺寸,移动端开发元素及字体尺寸适配基础知识
- QMake Automatic Dependencies
- Riot Blockchain再次购入1.5万台比特大陆S19系列矿机
- 通过system用户操作oracle数据库相关
- BZOJ-1050-[HAOI2006]旅行comf(并查集)
- 组建一个局域网一般会用到哪些设备_朋友私信一个简单的问题:端口和网关到底有什么区别?...
- 《关于促进大数据发展的行动纲要》提出三大指导意见
- 「建站指南」小白搭建网站一共分几步?
- 滤镜之瓷砖TileReflect
- 200行Python实现的qq连连看辅助,用于学习,请不要拿去伤害玩家
- 一名软件测试工程师的一天24小时(每天在忙什么)
- python之路_面向对象
- 计算机学院考研动员大会,计算机科学学院召开考研动员大会暨经验分享会
- 谷歌浏览器和火狐浏览器的12px字体显示大小不一样
- java心得!--很好的java学习历程(转自张国宝)
- JAVA 攻城狮 第三天