Android权限处理,不同版本的兼容

一、概述

Android权限机制的变化.主要以Android 6.0为分水岭.关于Android的权限机制变化的文章,网上的博客很多,我这里对自己开发过程中遇到的情况,进行的整理和分类,主要根据targetSdkVersion和Build.VERSION.SDK_INT的区别区分三种情况:

二、不同环境的分析

  1.  Android 6.0运行权限

    环境: Build.VERSION.SDK_INT >=23 并且应用targetSdkVersion >= 23

   检查相机权限: 使用方法  ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA);  

               《Android权限处理,不同版本的兼容》

  博客上的很多大神都有分析,大伙可以查看下面几篇文章:

         http://blog.csdn.net/lmj623565791/article/details/50709663  

         http://www.jianshu.com/p/dbe4d37731e6/ 


   2.   Android 6.0运行权限

            环境:Build.VERSION.SDK_INT >=23 并且应用targetSdkVersion <23

  注意:这里和上面的环境区别是:这里环境是在6.0以上的手机上运行,但是应用的targetSdkVersion是小于6.0的,

这就认定为该应用是旧版的应用,虽然还是在6.0以上的手机上运行,当我们这个时候使用下面方法再检查权限时就失效了:

            检查相机权限: 方法失效  ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA);  

可是Android6.0以上的手机,在设置中心的权限管理是可以手动修改应用的权限的,如果用户手动禁止了应用权限,特别是dangerous 权限,

如果我们不做检查判断处理的话,除了不能正常运行,而且应用在很多手机上会直接咔嚓掉.崩溃了怎么办.

这个时候就得使用方法:  PermissionChecker.checkSelfPermission(context, permission); 

     3.    Android 6.0以下的权限管理

     环境:Build.VERSION.SDK_INT< 23 并且应用targetSdkVersion <23

      本来原生的系统,在6.0以前我们在Manifest配置的权限都是默认打开的,在6.0以后是默认关闭的;

 这个6.0是指项目的targetSdkVersion>=23,而且运行在6.0以上的手机上.其他的都被认定为6.0以下的权限管理.

   
   原则上讲原生的Android 6.0以下权限时默认打开的,而且是用户不可以修改的,但是由于Android 不同的厂商的ROM定制,导致手机不同的版本,出现了本不应该有的权限管理设置,而且又加上手机管家的横行,导致我们应用开发人员也得对Android6.0以下的情况进行权限管理检测.
     这里我主要研究和参考了资料,:首先我找到了AppOps,查看他的源码,发现我需要的方法被隐藏了,于是我想到了通过发射来拿到@hide的方法,代码如下:

  1. /**
  2. * 反射调用系统权限,判断权限是否打开
  3. *
  4. * @param permissionCode 相应的权限所对应的code
  5. * @see {@link AppOpsManager }
  6. */
  7. private int checkPermission(int permissionCode) {
  8. int checkPermission = 0;
  9. if (Build.VERSION.SDK_INT >= 19) {
  10. AppOpsManager _manager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
  11. try {
  12. Class<?>[] types = new Class[]{int.class, int.class, String.class};
  13. Object[] args = new Object[]{permissionCode, Binder.getCallingUid(), mContext.getPackageName()};
  14. Method method = _manager.getClass().getDeclaredMethod("checkOp", types);
  15. method.setAccessible(true);
  16. Object _o = method.invoke(_manager, args);
  17. Log.e(TAG, "_o:" + _o);
  18. if ((_o instanceof Integer)) {
  19. checkPermission = (Integer) _o;
  20. }
  21. } catch (Exception e) {
  22. e.printStackTrace();
  23. }
  24. } else {
  25. checkPermission = 0;
  26. }
  27. return checkPermission;
  28. }

   于是我兴高采烈的哪去实验,
首先是小米3,
编译运行,开关权限测试,可以检测,完美,可是当我正要信誓旦旦的宣布,我太聪明的时候,

发现华为和联想手机运行无反应,不管怎么调试,检测的结果都是权限允许,心瞬间拔凉拔凉了.

简单分析原因,发现我是通过手机管家改变权限的,根本没有走Setting里面的AppOps类,所以我每次检测的值都是允许的状态.

可是怎么办,对于手机管家的改变我无能为力,最后只能妥协,换了一种方式,使用try catch,以及分贝的处理,对需要的权限进行检测,然后在捕捉到的异常中进行弹窗处理.

  1.  /**
         * 检查6.0以下语音权限
         */
        public boolean CheckRecordPermission(Context context) {
            //通过反射系列,可以检测出小米3c系列
            if (1 == checkPermission(RECORD_PERMISSION_CODE, context)) {
                return false;
            }
            initAudioRecord();
            try {
                mAudioRecord.startRecording();
            } catch (IllegalStateException e) {
                //通过try catch,可以检测出联想,三星系列
                releaseRecord();
                return false;
            }
            if (mAudioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
                //检测出联想,三星系列
                releaseRecord();
                return false;
            }
           int readSize = mAudioRecord.read(buffer, 0, buffer.length);
            //通过语音分贝可以检测出华为,oppo系列
            if (readSize <= 0) {
                releaseRecord();
                return false;
            } else {
                releaseRecord();
                return true;
            }
        }
    

最后发现这样处理,好算友好,基本适配所有机型,当然可能也有一些特定的手机无法支持

当然我这里要解释的是:

这针对6.0以下的无奈处理…

如果在6.0以上的情况,只做这种捕捉异常的方式是不行的,如果不做check()处理,程序就会出现异常的.

点击下载工具类源码

    原文作者:艳子的皮皮猪
    原文地址: https://blog.csdn.net/zybieku/article/details/52925928
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞