美文网首页AndroidAndroid知识
谈谈Android 6.0运行时权限理解

谈谈Android 6.0运行时权限理解

作者: 斜杠时光 | 来源:发表于2016-02-04 14:36 被阅读1020次

    前言

    谷歌在2015年8月份时候,发布了Android 6.0版本,代号叫做“棉花糖”(Marshmallow ),其中的很大的一部分变化,是在用户权限授权上,或许是感觉之前默认授权的不合理,现在6.0出来,使得用户权限授权变得合理。这可能也是参考IOS系统的,只有在用户需要使用权限的时候,才去授权请求,这样做的目的是提高用户体验,当然,用户感觉好了,受苦的是我们开发人员,原来的规则不适用了,现在我们去适应新的规则,毕竟是靠谷歌这颗大树吃饭的嘛。

    原来权限模型

    在Android 6.0版本之前,权限都是一条龙服务的,只要用户安装完,
    AndroidManifest清单上申请的权限都会被系统默认授权,并且授权后也撤销不了。这样的弊端在哪里呢?有些权限可能用户觉得不需要,比如他不想有通知的权限,不想受到通知的干扰,那么他就不能屏蔽通知,就是不需要的权限,他去不掉,自主权不在他那边。还有一些情况是,一些恶意程序,会利用这个权限默认授权,进行恶意获取用户数据和攻击。所以Android 6.0版本,一方面让用户更加容易的控制自己的隐私,一方面需要重新适配应用权限。

    Android 6.0权限模型

    采用新的权限模型,只有在需要权限的时候,才告知用户是否授权,是在runtime时候授权,而不是在原来安装的时候 ,
    同时默认情况下每次在运行时打开页面时候,需要先检查是否有所需要的权限申请。这样的用户的自主性提高很多,比如用户可以给APP赋予摄像的权限,但是可以拒绝记录设备位置的权限,就是怕位置信息上传等等。

    权限流程

    在API 23中,权限满足的标准流程:


    系统授权弹窗流程

    但这里有个问题,那就是在系统授权弹窗环节,提醒框会有个不再提示的复选框,如果用户点击不太提示,并拒绝授权,那么再下次授权的时候,系统授权弹窗的提示框就不会在提示,所以我们很有必要需要自定义权限弹窗提示框,那么流程图就变成如下了。


    自定义权限弹窗流程

    权限类型

    权限类型

    在图中,我们可以看到整个权限里,可以分为系统权限和特殊权限授权。
    系统权限中,又分为normal和dangerous类型。

    • normal:这个权限类型并不直接威胁到用户的隐私,可以直接在manifest清单里注册,系统会帮我们默认授权的。
    • dangerous:这个可以直接给app访问用户一些敏感的数据,不仅需要在manifest清单里注册,同时在使用的时候,需要向系统请求授权。
    • 值得注意一点,这里有特殊权限授权的区别,分别是
      SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS,虽然这两个权限也是属于dangerous权限类型,但是这两个授权请求方式和其他dangerous权限是不一样的,需要特殊处理 。

    normal列表:


    dangerous列表:

    版本兼容

    • 当然,谷歌也是考虑到如果是以API 23之前的版本编译的APP,在6.0的系统上运行,还是能兼容的。如果是23之前的版本编译的APP,则权限模型走的是老的模式,也就是在一条龙的模式,在manifest清单注册,系统会帮我们默认授权,并且也能运行。
    • 但如果是以API 23的版本编译的APP,那走的的必须是新的权限模型,在遇到dangerous权限的时候,必须进行授权的,如果没有进行授权话,系统则会提示崩溃信息。所以,基于6.0系统的开发的程序, 在打开页面的时候,必须要考虑这个页面是否用到需要授权的权限,页面检测是否已经授权过了没。

    实现方式

    第一步:检测权限
    // Assume thisActivity is the current activity
    int permissionCheck = ContextCompat.checkSelfPermission(this Activity, Manifest.permission.WRITE_CALENDAR); 
    
    第二步:请求权限
    // Here, thisActivity is the current activity
    if (ContextCompat.checkSelfPermission(this Activity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {  
      // Should we show an explanation? 
    if (ActivityCompat.shouldShowRequestPermissionRationale(this Activity, Manifest.permission.READ_CONTACTS)) {      
      // Show an expanation to the user *asynchronously* -- don't block       
      // this thread waiting for the user's response! After the user   
      // sees the explanation, try again to request the permission.   
    } 
    else {       
      // No explanation needed, we can request the permission.   
      ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
      //MY_PERMISSIONS_REQUEST_READ_CONTACTS is an        
      // app-defined int constant. The callback method gets the       
      // result of the request.  
     }
    }
    
    第三步:处理权限请求结果
    @Override
    public void onRequestPermissionsResult(int requestCode,String permissions[], int[] grantResults) {    
    switch (requestCode) {        
      case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {            
          // If request is cancelled, the result arrays are empty.            
          if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                
          // permission was granted, yay! Do the                
          // contacts-related task you need to do.            
          } else {                
          // permission denied, boo! Disable the                
          // functionality that depends on this permission.            
          }            
          return;        
        }        
       // other 'case' lines to check for other        
       // permissions this app might request    
      }
    }
    

    其中要特别注意的是,如果是针对android.permission.SYSTEM_ALERT_WINDOW
    android.permission.WRITE_SETTINGS,这两个权限,实现方式跟上面三步骤是不一样的,需要另外特殊处理。

    具体代码:

    Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
    intent.setData(Uri.parse("package:" + getPackageName()));
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
    

    注意点

    之前在工作中,碰到一种情况,如果是运行在6.0的版本上是需要走新的权限模型,如果是运行在老的版本上,则需要进行一个判断,此时碰到一个问题是,在谷歌官方推荐中,在判断app运行的系统是否在Android M上时,它的判断是如下: Build.VERSION.CODENAME.equals("MNC"); 可是在我实际适配中,发现这句却无效的,就改用Build.VERSION.SDK_INT >= 23。


    总结

    • 首先要知道6.0版本权限模型跟原来版本是不同的,不再是统一在manifest中默认系统授权,而是有需要的时候,向系统请求授权,提高用户体验。
    • 了解权限检测流程,一点注意点是如果系统权限弹窗提示框被不再提醒了,需要我们自定义提示弹窗,引导用户去授权。
    • 明白权限类型,分为normal和dangerous类型,同时,在dangerous中还需要注意一点,SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS这两个特殊授权请求方式,跟一般授权请求方式不同。
    • 在判断APP是否运行在Android M上,可以用版本号来判断,可以准确点。

    参考

    有个具体demo:https://github.com/SpikeKing/wcl-permission-demo
    流程图:http://blog.csdn.net/caroline_wendy/article/details/50587230

    相关文章

      网友评论

      • Zmylls:楼主,如果系统对话框不在提醒了,需要自己做引导。那该怎么引导呢?又加一个对话框,对话框有设置和取消按钮,那不又回到之前系统的对话框了?
        斜杠时光:@耀舞夕阳 一般系统对话框不在提醒的话,可能的情况是用户拒绝授权,那就需要跟用户提示拒绝授权可能使用不来该页面之类,现在6.0的用户授权跟ios中很像,当用到某个权限的时候才去申请,所以需要说明。

      本文标题:谈谈Android 6.0运行时权限理解

      本文链接:https://www.haomeiwen.com/subject/qpmekttx.html