美文网首页
Android6.0动态权限第三方安全中心权限踩坑

Android6.0动态权限第三方安全中心权限踩坑

作者: 梦半觉 | 来源:发表于2017-07-07 22:16 被阅读200次

一、概述

Android6.0由于考虑到安全性,把系统权限收紧了,需要在app程序运行时动态地去向用户申请权限。

二、示例

以申请录音权限为例:

//检查是否有录音权限
        boolean isAllGranted = PermissionUtils.checkPermissionAllGranted(this, new
                String[]{Manifest.permission.RECORD_AUDIO});
        if (isAllGranted) {//如果有录音权限
            //do some thing
        } else {
            //请求录音权限
            PermissionUtils.requestPermission(AskForHelpActivity.this, new String[]{Manifest
                    .permission.RECORD_AUDIO});
        }

其中用到了PermissionUtils这个我自己简单封装的工具类

public class PermissionUtils {

    public static final int UTILS_PERMISSION_REQUEST_CODE = 8069;//工具类权限请求码

    /**
     * 检查是否拥有指定的所有权限
     *
     * @param mContext
     * @param permissions
     * @return
     */
    public static boolean checkPermissionAllGranted(Context mContext, String[] permissions) {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (String permission : permissions) {
                if (ContextCompat.checkSelfPermission(mContext, permission) != PackageManager
                        .PERMISSION_GRANTED) {
                    // 只要有一个权限没有被授予, 则直接返回 false
                    return false;
                }
            }
            //安卓原生权限管理 适配小米等第三方
            AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(Context
                    .APP_OPS_SERVICE);
            int checkOp = appOpsManager.checkOp(AppOpsManager.OPSTR_FINE_LOCATION, Process.myUid
                    (), mContext
                    .getPackageName());
            if (checkOp != AppOpsManager.MODE_IGNORED) {
                return false;
            }
        }

        return true;
    }

    /**
     * 一次请求多个权限, 如果其他有权限是已经授予的将会自动忽略掉
     *
     * @param activity
     * @param permissions
     */
    public static void requestPermission(Activity activity, String[] permissions) {
        ActivityCompat.requestPermissions(activity, permissions, UTILS_PERMISSION_REQUEST_CODE);
    }

}

经过本人测试发现v4包下的ContextCompatcheckSelfPermission去动态检测权限时,如果用户已经拒绝了该权限,就算你手动去系统的 应用信息 --> 权限 中开启,小米等第三方还是会在你检测权限时返回flase,即无权限
因此需要采用Android原生的权限管理(AppOpsManager这个类)来解决这个问题,即上面的这段关键代码(坑的我好苦啊~ 0.0):

//安卓原生权限管理 适配小米等第三方
            AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(Context
                    .APP_OPS_SERVICE);
            int checkOp = appOpsManager.checkOp(AppOpsManager.OPSTR_FINE_LOCATION, Process.myUid
                    (), mContext
                    .getPackageName());
            if (checkOp != AppOpsManager.MODE_IGNORED) {
                return false;
            }

三、补充

为了更好的用户体验,你应该对申请结果做处理,在用户拒绝权限时,应该友善地引导用户去理解这个权限的用处。

/**
     * 申请权限结果返回处理
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] 
            grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == UTILS_PERMISSION_REQUEST_CODE) {
            boolean isAllGranted = true;
            // 判断是否所有的权限都已经授予了
            for (int grant : grantResults) {
                if (grant != PackageManager.PERMISSION_GRANTED) {
                    isAllGranted = false;
                    break;
                }
            }
            if (isAllGranted) {
                // 如果所有的权限都授予了
                //do some thing
            } else {
                // 弹出对话框告诉用户需要权限的原因, 并引导用户去应用权限管理中手动打开权限按钮
                openAppDetails();
            }
        }
    }

    /**
     * 打开 APP 的详情设置
     */
    private void openAppDetails() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("应用需要 “录音” 权限,请到 “应用信息 -> 权限” 中授予!");
        builder.setPositiveButton("去手动授权", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Intent intent = new Intent();
                intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                intent.addCategory(Intent.CATEGORY_DEFAULT);
                intent.setData(Uri.parse("package:" + getPackageName()));
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                startActivity(intent);
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                finish();
            }
        }).setCancelable(false).show();
    }

四、修正

工具类:

public class PermissionUtils {

    public static final int UTILS_PERMISSION_REQUEST_CODE = 8069;//工具类权限请求码

    /**
     * 检查是否拥有指定的所有权限
     *
     * @param mContext
     * @param normalPermissions
     * @return
     */
    public static boolean checkPermissionAllGranted(Context mContext, List<String>
            normalPermissions) {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (String permission : normalPermissions) {
                int checkSelf = ContextCompat.checkSelfPermission(mContext, permission);
                if (checkSelf != PackageManager.PERMISSION_GRANTED) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 检查是否拥有指定的所有权限
     *
     * @param mContext
     * @param normalPermissions
     * @param appOpsPermissions 为了适配小米
     * @return
     */
    public static boolean checkPermissionAllGranted(Context mContext, List<String>
            normalPermissions, List<String> appOpsPermissions) {
        boolean checkSelfResult = true;
        boolean checkOpResult = true;
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (String permission : normalPermissions) {
                int checkSelf = ContextCompat.checkSelfPermission(mContext, permission);
                if (checkSelf != PackageManager.PERMISSION_GRANTED) {
                    checkSelfResult = false;
                }
            }
        }
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (String appOpsPermission : appOpsPermissions) {
                //安卓原生权限管理 适配小米等第三方
                AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(Context
                        .APP_OPS_SERVICE);
                int checkOp = appOpsManager.checkOp(appOpsPermission, Process.myUid(), mContext
                        .getPackageName());
                switch (checkOp){
                    case AppOpsManager.MODE_ALLOWED:
                        Log.d("PermissionUtils", "权限:允许");
                        checkOpResult = true;
                        break;
                    case AppOpsManager.MODE_IGNORED:
                        Log.d("PermissionUtils", "权限:拒绝");
                        checkOpResult = false;
                        break;
                    case AppOpsManager.MODE_ERRORED:
                        Log.d("PermissionUtils", "权限:错误");
                        checkOpResult = false;
                        break;
                    case 4:
                        Log.d("PermissionUtils", "权限:询问");
                        checkOpResult = false;
                        break;
                    default:
                        checkOpResult = false;
                        break;
                }
            }
        }
        return (checkSelfResult && checkOpResult);
    }


    /**
     * 一次请求多个权限, 如果其他有权限是已经授予的将会自动忽略掉
     *
     * @param activity
     * @param normalPermissions
     */
    public static void requestPermission(Activity activity, List<String> normalPermissions) {
        int normalPermissionsNumber = normalPermissions.size();
        ActivityCompat.requestPermissions(activity, normalPermissions.toArray(new
                String[normalPermissionsNumber]), UTILS_PERMISSION_REQUEST_CODE);
    }

}

使用

 List<String> normalPermissions = new ArrayList<String>();//权限列表
    //适配小米
 List<String> appOpPermissions = new ArrayList<String>();//权限列表
 normalPermissions.add(Manifest.permission.RECORD_AUDIO); //录音权限
        normalPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION);//定位精确位置
        //适配小米
        appOpPermissions.clear();
        appOpPermissions.add(AppOpsManager.OPSTR_RECORD_AUDIO);//录音权限
        appOpPermissions.add(AppOpsManager.OPSTR_FINE_LOCATION);//定位精确位置
        //检查权限
        boolean isAllGranted = PermissionUtils.checkPermissionAllGranted(this, normalPermissions,
                appOpPermissions);
        if (isAllGranted) {//如果所有权限都有
            //do some thing
        } else {
            //请求所有权限
            PermissionUtils.requestPermission(AskForHelpActivity.this, normalPermissions);
        }

相关文章

网友评论

      本文标题:Android6.0动态权限第三方安全中心权限踩坑

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