Marshmallow版本权限修改

  android的权限系统一直是首要的安全概念,因为这些权限只在安装的时候被询问一次。一旦安装了,app可以在用户毫不知晓的情况下访问权限内的所有东西,而且一般用户安装的时候很少会去仔细看权限列表,更不会去深入了解这些权限可能带来的相关危害。但是在android 6.0 Marshmallow版本之后,系统不会在软件安装的时候就赋予该app所有其申请的权限,对于一些危险级别的权限,app需要在运行时一个一个询问用户授予权限。

  

旧版本app兼容问题

  那么问题来了,是不是所有以前发布的app都会出现问题呢?答案是不会,只有那些targetSdkVersion 设置为23及以上的应用才会出现异常,在使用危险权限的时候系统必须要获得用户的同意才能使用,要不然应用就会崩溃,出现类似下面的错误。

java.lang.SecurityException: Permission Denial...

所以targetSdkVersion如果没有设置为23版本或者以上,系统还是会使用旧规则:在安装的时候赋予该app所申请的所有权限。所以app当然可以和以前一样正常使用了,但是还有一点需要注意的是6.0的系统里面,用户可以手动将该app的权限关闭,在 App info里面Permissions下边,可以关闭某个权限。如果以前的老应用申请的权限被用户手动关闭了,不会抛出异常,不会崩溃,只不过调用那些被用户禁止权限的api接口返回值都为null或者0,所以我们只需要做一下判空操作就可以了,这是需要注意的。

普通权限和危险权限列表

  现在对于新版本的权限变更应该有了基本的认识,那么,是不是所有权限都需要去进行特殊处理呢?当然不是,只有那些危险级别的权限才需要,可参考官网。

  http://developer.android.com/training/permissions/requesting.html 
  http://developer.android.com/guide/topics/security/permissions.html#normal-dangerous 
  所以仔细去看看自己的app,对照列表,如果有需要申请其中的一个权限,就需要进行特殊操作。还有一个比较人性的地方就是如果同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE_EXTERNAL_STORAGE被授权了,app也有READ_EXTERNAL_STORAGE权限了。

支持Marshmallow新版本权限机制

  在Android M的api中,我们可以通过checkSelfPermission检测软件是否有某一项权限,以及使用requestPermissions去请求一组权限。

int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
CODE_FOR_WRITE_PERMISSION);
return;
}

  以上的代码块展示了检测软件是否有写文件的权限,如果没有写文件的权限,则通过requestPermissions去向用户发起请求权限的流程。向用户发起请求之后,请求完成,会有相对应的回调方法,通知软件用户是否授予了权限。通过在Activity或者Fragment中重写onRequestPermissionsResult方法。  

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == CODE_FOR_WRITE_PERMISSION){
if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)
&& grantResults[0] == PackageManager.PERMISSION_GRANTED){
// 用户同意写文件
} else {
// 用户不同意,自行处理即可
}
}
}

处理不再提醒

  如果用户一旦拒绝过某权限的授权。下一次弹框时,用户会有一个“不再提醒(Never ask again)”的选项的来防止app以后继续请求授权。

  

  如果这个选项在拒绝授权前被用户勾选了。下次为这个权限请求requestPermissions时,对话框就不弹出来了,系统会直接回调onRequestPermissionsResult函数,回调结果为最后一次用户的选择。所以为了应对这种情况,系统提供了一个shouldShowRequestPermissionRationale()函数,这个函数的作用是帮助开发者找到需要向用户额外解释权限的情况。

  1. 应用安装后第一次访问,直接返回false;
  2. 第一次请求权限时,用户拒绝了,下一次shouldShowRequestPermissionRationale()返回 true,这时候可以显示一些为什么需要这个权限的说明;
  3. 第二次请求权限时,用户拒绝了,并选择了“不再提醒”的选项时:shouldShowRequestPermissionRationale()返回 false;
  4. 设备的系统设置中禁止当前应用获取这个权限的授权,shouldShowRequestPermissionRationale()返回false;

注意:第二次请求权限时,才会有“不再提醒”的选项,如果用户一直拒绝,并没有选择“不再提醒”的选项,下次请求权限时,会继续有“不再提醒”的选项,并且shouldShowRequestPermissionRationale()也会一直返回true。

所以利用这个函数我们可以进行相应的优化,针对shouldShowRequestPermissionRationale函数返回false的处理有两种方法:

  处理方法已经有了,修改一下代码,这里以第二种方案来处理:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == CODE_FOR_WRITE_PERMISSION){
if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)
&&grantResults[0] == PackageManager.PERMISSION_GRANTED){
// 用户同意
} else {
// 用户不同意,向用户展示该权限作用
if (!shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
showPermissionDialog();return;
}
}
}
}

当勾选不再提醒,并且拒绝之后,弹出dialog,提醒用户该权限的重要性

使用兼容库

  以上的代码在6.0版本上使用没有问题,但是在之前就有问题了,最简单粗暴的解决方法可能就是利用Build.VERSION.SDK_INT >= 23这个判断语句来判断了,方便的是SDK 23的v4包加入了专门类进行相关的处理:

  • ContextCompat.checkSelfPermission()被授权函数返回PERMISSION_GRANTED,否则返回PERMISSION_DENIED ,在所有版本都是如此。
  • ActivityCompat.requestPermissions()这个方法在6.0之前版本调用,OnRequestPermissionsResultCallback 直接被调用,带着正确的 PERMISSION_GRANTED或者PERMISSION_DENIED。
  • ActivityCompat.shouldShowRequestPermissionRationale()在6.0之前版本调用,永远返回false。
// 使用兼容库就无需判断系统版本
int hasWriteContactsPermission = ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (hasWriteContactsPermission == PackageManager.PERMISSION_GRANTED) { } // 需要弹出dialog让用户手动赋予权限
else {
ActivityCompat.requestPermissions(Acivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, CODE_FOR_WRITE_PERMISSION);
}

onRequestPermissionsResult函数不变。后两个方法,我们也可以在Fragment中使用,用v13兼容包:FragmentCompat.requestPermissions() 和 FragmentCompat.shouldShowRequestPermissionRationale()和activity效果一样。

一次请求多个权限

  当然了有时候需要多个权限,可以用上面方法一次请求多个权限。当然最重要的是不要忘了为每个权限检查“不再提醒”的设置。

List<String> permissionsNeeded = new ArrayList<String>();
permissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
permissionsNeeded.add(Manifest.permission.READ_CONTACTS);
permissionsNeeded.add(Manifest.permission.WRITE_CONTACTS);
requestPermissions(permissionsNeeded.toArray(new String[permissionsList.size()]), CODE_FOR_MULTIPLE_PERMISSION);

最后在onRequestPermissionsResult函数中一个个处理返回结果即可。

第三方库简化代码

  当然早就有第三方库来帮忙做这些事情了: 
  Github上的开源项目 PermissionHelperPermissionsDispatcherEasyPermissions

APP处于运行状态下,被撤销权限

  如果APP正在运行中,用户进入设置-应用程序页面去手动撤销该APP权限,会出现什么情况呢?系统又会接着弹出权限请求对话框。

Over

  新运行时权限已经在棉花糖中被使用了。我们没有退路。我们现在唯一能做的就是保证app适配新权限模型。欣慰的是只有少数权限需要运行时权限模型。大多数常用的权限,例如,网络访问,属于Normal Permission 在安装时自动会授权,当然你要声明,以后无需检查。因此,只有少部分代码你需要修改。 
两个建议: 
  1.严肃对待新权限模型。 
  2.如果你代码没支持新权限,不要设置targetSdkVersion 23 。尤其是当你在Studio新建工程时,不要忘了修改! 
  说一下代码修改。这是大事,如果代码结构被设计的不够好,你需要一些很蛋疼的重构。每个app都要被修正。如上所说,我们没的选择。列出所有你需要请求权限的全部情形,如果A被授权,B被拒绝,会发生什么,针对每一个情况认真处理。

Android 6.0 Permission权限与安全机制的更多相关文章

  1. Android 6.0的权限问题

    Android 6.0的权限获取不同于别的版本,具体的实例如下: if (ContextCompat.checkSelfPermission(this, Manifest.permission.REA ...

  2. android 6.0+ 动态权限 拒绝不再询问后跳转设置应用详情页面

    android 6.0+ 的权限 需要动态申请 这里的权限针对的是 敏感权限: SMS(短信) SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEI ...

  3. android 6.0 动态权限

    Android 6.0 动态权限: 除了要在AndroidManifest.xml中申请外,还需使用时,请求用户允许授权. 以下是需要单独申请的权限,共分为9组,每组只要有一个权限申请成功了,就默认整 ...

  4. Android 6.0 - 动态权限管理的解决方案(转)

    转自:http://www.cnblogs.com/dubo-/p/6018262.html Android 6.0 - 动态权限管理的解决方案   转载请标注 Android 6.0版本(Api 2 ...

  5. Android开发之深入理解Android 7.0系统权限更改相关文档

    http://www.cnblogs.com/dazhao/p/6547811.html 摘要: Android 6.0之后的版本增加了运行时权限,应用程序在执行每个需要系统权限的功能时,需要添加权限 ...

  6. Android 6.0动态权限申请

    转载(Android 6.0 动态权限申请简单简洁优雅的处理方式): https://blog.csdn.net/lin_dianwei/article/details/79025324

  7. Android 6.0 - 动态权限管理的解决方案

    Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用户体验, 同时也为程序员带来新的负担. 动态权限管理就是这样, 一方面让用户更加容易的控制自己的隐私, 一方面需要重新适配应 ...

  8. Android 开发技巧 - Android 6.0 以上权限大坑和权限检查基类封装

    简单介绍 关于运行时权限的说法,早在Google发布android 6.0的时候,大家也听得蛮多的.从用户的角度来讲,用户是受益方,更好的保护用户的意思,而对于开发者来说,无疑增加了工作量. 对于6. ...

  9. Android 6.0 动态权限申请注意事项

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/uana_777/article/details/54136255 Part One 权限区分 And ...

随机推荐

  1. /usr/bin/ld: cannot find *** 的处理

    /usr/bin/ld: cannot find *** 的处理

  2. 基于粒子群算法求解求解TSP问题(JAVA)

    一.TSP问题 TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选 ...

  3. 设置button 不可被点击

    mGetCode.setEnabled(false);//不可被点击 mGetCode.setEnabled(true);//可被点击 bt.setClickable(true);//设置点击为tru ...

  4. eclipse中使用tomcat图解

    配置步骤: 1. tomcat7是绿色软件,解压后即可使用,请大家先将tomcat解压到合适的位置(建议整个路径都是英文路径), 2. 打开eclipse,菜单栏下,File--New--Other. ...

  5. JMeter Tutorial的安装和具体操作

    1.下载Jmeter 下载地址:http://jmeter.apache.org/download_jmeter.cgi 目前最新版为2.9,其余文件如源代码等也可从如下官网下载: http://jm ...

  6. Android 获取WIFI MAC地址的方法

    1. 经常用法,调用Android的API:WifiManager <uses-permission android:name="android.permission.ACCESS_W ...

  7. 王灏:光音网络致力打造Wi-Fi大生态圈

    光音网络,做的是本地网络综合服务.在中国,想把互联网做到覆盖延伸范围之外的最后100米,光音网络是当中一家,也是最坚持的一家.为千万家本地生活商户提供帮助,为数亿本地用户提供最佳的本地网络体验,这是光 ...

  8. CentOS Nginx+jdk+tomcat 环境搭建

    一.jdk安装 jdk下载地址:http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloa ...

  9. 【NodeJs】用arrayObject.join('')处理粘包的错误原因

    服务器测试代码如下: var net = require('net'); var server = net.createServer(function(c){ console.log('client ...

  10. RedHat7 SELinux

    SELinux(Security-Enhanced Linux) 是美国国家安全局(NSA)对于强制访问控制的实现,是 Linux历史上最杰出的新安全子系统.NSA是在Linux社区的帮助下开发了一种 ...