Android 6.0 权限机制等新特性

1、电源管理

App Standby(应用待机)

  • 检测:当设备未充电,且在这段时间內用户没有直接或者间接的启动该应用。
  • 退出:当应用激活时,或者设备充电时,系统将应用移除此状态。

Doze

  • 检测:当设备未充电,且当设备静止或灭屏一段时间
  • 周期:平台尝试让系统处于休眠状态,周期性地进入在一个维持窗口恢复正常操作,然后进入更长的休眠状态
    (理解:如果用户不操作手机,android先进入一个休眠状态,过段时间再检测还是未操作,就进入下一级休眠状态,以此类推,知道进入最高级别的休眠状态,以达到省电)

2、App Link(非新,加强力度)

  • 全称为 应用程序链接
  • 技术点: 就是隐式启动Intent
  • android更加鼓励应用程序间的关联而不再是单一的应用同浏览器的交互

指纹识别

  • 6.0以前一直由各手机制造厂商去研发,导致指纹识别不同的手机差异巨大
  • 6.0以后将由android系统提供api,硬件厂商只需提供相应的硬件支持即可

3、应用程序权限管理

权限机制

  • 5.0以前,只需要manifest.xml中注册声明即可
  • 5.0以后,用户可以在安装的时候关闭某些权限
  • 6.0及以后,对于一些用户隐私权限总是会在第一次提示用户是否授予权限(类似iPhone)

运行时权限的优势

  • 新的权限机制更好的保护了用户的隐私
  • 给了程序向用户说明权限的作用
  • 可以防止一些恶意程序盗取用户或者手机信息,增强了android系统的安全性

运行时权限的分类

  • Normal Premission

一些不涉及隐私的权限,不需要单独去申请,只需要在manifest申请就可以

  • Dangerous Permission & Dangerous Premission Group

涉及隐私的权限,会在运行时向用户申请。并且会分单独的权限和权限组的形式。例如:读sd卡和写sd卡可以合并成操作sd卡的组形式的权限组

权限组的概念

  • 如果你申请某个危险的权限,假设你的app早已被用户授权了同一个组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权

新权限使用实例

新增API

  • ContextCompact.checkSelfPermission()

    检测app是否拥有此权限

  • ActivityCompat.requestPermissions()

    申请某个权限

  • onRequestPermissionsResult()

    申请权限的回调,处理申请权限成功失败

  • ActivityCompat.shouldShowRequestPermissionRationale

    用于给用户解释申请改权限是用于做什么的。用户拒绝我们的申请之后才会出现

使用流程

  • 在AndroidManifest中添加需要的权限(不可省)

  • 检查权限

      shell命令:
      adb shell pm list permissions -d -g
    
  • 申请授权

  • 处理申请回调

代码实战

  • 运用上述流程实现一个拨打电话的权限请求过程

    1、先在AndroidManifest.xml中注册权限

      <uses-permission android:name="android.permission.CALL_PHONE"/>
    

    2、在MainActivity中检查权限,如果有直接执行拨打电话。如果没有权限,请求权限

      if(ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
              != PackageManager.PERMISSION_GRANTED){
          // 做权限申请处理
          ActivityCompat.requestPermissions(this, 
              new String[]{Manifest.permission.CALL_PHONE}, Constants.CALL_PHONE);
      }else{
          // 已经有改权限
          doCallPhone();// 拨打电话的具体实现
      }
    

    3、处理onRequestPermissionsResult回调

      @Override
      public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
          super.onRequestPermissionsResult(requestCode, permissions, grantResults);
          switch (requestCode){
              case Constants.CALL_PHONE:
                  if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                      doCallPhone();
                  }else{
                      // 请求被拒绝,提示用户
                      Snackbar.make(fabCall, "拨打电话权限被拒绝", Snackbar.LENGTH_SHORT).show();
                  }
                  break;
          }
      }
    
  • 当前我们只添加了一个权限,代码就很臃肿了,所以可以考虑封装我们请求权限的代码到BaseActivity中。

    BaseActivity.java

      public class BaseActivity extends AppCompatActivity {
      
          public boolean hasPermission(String... permissions){
              for(String per : permissions){
                  if(ContextCompat.checkSelfPermission(this, per)
                          != PackageManager.PERMISSION_GRANTED){
                      return false;
                  }
              }
              return true;
          }
      
          public void requestPermission(int code, String... permissions){
              ActivityCompat.requestPermissions(this, permissions, code);
          }
      
          @Override
          public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
              super.onRequestPermissionsResult(requestCode, permissions, grantResults);
              switch(requestCode){
                  case Constants.WRITE_EXTERNAL_CODE:
                      if(isAllGranted(grantResults)){
                          onWriteExternalGranted();
                      }else{
                          onWriteExternalDenied();
                      }
                  break;
              }
          }
      
          private boolean isAllGranted(int[] grantResults) {
              for(int result : grantResults){
                  if(result != PackageManager.PERMISSION_GRANTED){
                      return false;
                  }
              }
              return true;
          }
      
          protected void onWriteExternalDenied() {}
      
          protected void onWriteExternalGranted(){};
      }
    
  • MainActivity 继承 BaseActivity,实现在download目录下新建一个文件

    判断是否有权限。有,直接操作,没有,请求权限。

      if(hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
              Manifest.permission.READ_EXTERNAL_STORAGE)){
          doCreateFile(); // 新建文件具体实现
      }else{
          requestPermission(Constants.WRITE_EXTERNAL_CODE,
                  Manifest.permission.WRITE_EXTERNAL_STORAGE,
                  Manifest.permission.READ_EXTERNAL_STORAGE);
      }
    

    复写成功失败方法

      @Override
      protected void onWriteExternalDenied() {
          Snackbar.make(fabSD, "获取文件权限失败", Snackbar.LENGTH_SHORT).show();
      }
    
      @Override
      protected void onWriteExternalGranted() {
          doCreateFile();
      }
    

    这样虽然没有一个权限申请都需要复写一套成功失败的回调,但已经简洁了很多,而且加上注释逻辑也很清晰

  • 第三方库实现 录音权限申请

    也可以借用第三方的库来实现,这里采用的是一个注解库

  • 使用方法

    加入引用

      compile 'com.lovedise:permissiongen:0.0.6'
    

    请求权限

      PermissionGen.needPermission(this, Constants.RECORD_AUDIO,
              new String[]{
                      Manifest.permission.RECORD_AUDIO
              });
    

    在onRequestPermissionsResult注册该库的方法。

      @Override
      public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
          super.onRequestPermissionsResult(requestCode, permissions, grantResults);
          PermissionGen.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
      }
    

    成功回调

      @PermissionSuccess(requestCode = Constants.RECORD_AUDIO)
      public void doRecordSounds(){
          Snackbar.make(fabMic, "录音中...", Snackbar.LENGTH_SHORT).show();
      }
    

    失败回调

      @PermissionFail(requestCode = Constants.RECORD_AUDIO)
      public void onPremissionDenied(){
          Snackbar.make(fabMic, "没有录音权限", Snackbar.LENGTH_SHORT).show();
      }
    

    最后,第三方库虽然使用方便,但注解时反射会影响运行时的速度。使用时需要考虑。

Constants.java

public class Constants {
    public static final int WRITE_EXTERNAL_CODE = 0x000;
    public static final int CALL_PHONE = 0x001;
    public static final int RECORD_AUDIO = 0x002;
}

本文总结自qandroid老师慕课网Android 6.0新特性课程。###

然后你们最爱的源码###

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容