亲测有效:Android权限申请简易封装带结果回调

权限申请结果只能在活动(指activity/fragment)里面获取,在非活动里面是获取不到的,所以需要一个透明的activity进行requestPermissions申请权限、onRequestPermissionsResult请求权限结果并回调回去。

一开始尝试封装在非活动类里面获取申请结果,查找资料后有人说只要用如下方法:

注:此方法是行不通的,走不到onRequestPermissionsResult里面

public class PermissionTestUtils implements ActivityCompat.OnRequestPermissionsResultCallback {
  @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 申请权限的requestCode) {
            //处理判断权限是否授权的逻辑      
        }
    }
}

 思路:上层申请权限(带结果回调授权成功、拒绝、拒绝且不再询问,具体要什么回调按需求来)——》校验权限是否都存在——》不存在则弹出提示用户需要申请什么权限,为什么要申请。用户同意后——》申请权限,把申请结果回调回去,若是用户选择了拒绝且不再询问则引导用户去设置页开启什么权限。

在开始前,需要了解到几个重要方法:

1.ContextCompat.checkSelfPermission(context, permission)校验权限是否已授权
2.ActivityCompat.requestPermissions(this, permissions, request_permissions_code申请权限
3.ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)是否勾选不再询问,在onRequestPermissionsResult中用

一.PermissionTestListener权限结果回调类:按需来设计

/**
 * onDenied、onAskAgain某些情况会回都回调,申请多个权限ABCD,第一次我拒绝且不再询问权限A,后面拒绝BCD任何一个,
 * 所以上层一般不处理拒绝的回调,统一处理“拒绝且不再询问”后去引导用户设置
 */
public interface PermissionTestListener {
    void onGranted(String[] grPermission);//授权(全部权限都授权时才回调)

    void onDenied(List dePermissions);//拒绝

    void onAskAgain(List asPermissions);//拒绝且不再询问
}

 二.PermissionTestUtils权限工具类:校验权限是否存在,申请权限统一入口等

public class PermissionTestUtils {
    private static String TAG = PermissionTestUtils.class.getSimpleName();

    /**
     * 校验权限是否都授权(只要有一个没有授权就是false)
     *
     * @param context
     * @param permissions
     * @return
     */
    public static boolean checkSelPermission(Context context, String... permissions) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // 判断sdk版本
            return true;
        }
        for (String permission : permissions) {
            //没有授权:PackageManager.PERMISSION_DENIED;已授权:PackageManager.PERMISSION_GRANTED;用PERMISSION_GRANTED来判断
            if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }


    /**
     * 校验权限是否都授权
     *
     * @param context
     * @param permissions
     * @return 返回没有授权的string[]
     */
    public static String[] checkSelPermissionStr(Context context, String... permissions) {

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // 判断sdk版本
            return null;
        }
        List stringList = new ArrayList<>();
        //循环遍历所申请的所有权限,看看是否都申请到了;但凡有一个没有申请,那就立即去申请
        for (String permission : permissions) {
            //没有授权:PackageManager.PERMISSION_DENIED;已授权:PackageManager.PERMISSION_GRANTED
            if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {//这个权限没有申请到
                stringList.add(permission);
            }
        }
        if (stringList != null || stringList.size() > 0) {
            String[] permissionDenied = new String[stringList.size()];//没有权限的数组
            for (int i = 0; i < stringList.size(); i++) {
                permissionDenied[i] = stringList.get(i);
            }
            return permissionDenied;
        } else {
            return null;
        }
    }

    /**
     * 检验权限结果是否都授权(onRequestPermissionsResult()里面调用)
     *
     * @param grantResults
     * @return 有一个没有授权成功就返回false
     */
    public static boolean checkGrantResults(int[] grantResults) {
        boolean grant = true;
        if (grantResults != null && grantResults.length > 0) {
            for (int grantResult : grantResults) {
                //没有授权:PackageManager.PERMISSION_DENIED;已授权:PackageManager.PERMISSION_GRANTED
                if (grantResult != PackageManager.PERMISSION_GRANTED) {
                    grant = false;
                    break;
                }
            }
        }
        return grant;
    }

    /**
     * 判断用户是否勾选不再提示 返回false
     * true:之前请求过此权限但拒绝了,但是没有勾选不再提示;
     * false:1.之前请求拒绝了且勾选不再提示(那就不能再提示了);2.之前没有拒绝过即第一次申请(两种情况都返回false)
     * 所以在onRequestPermissionsResult()方法里面用,不在requestPermissions()申请权限前用,因无法判断false具体是哪个
     */
    public static boolean checkShouldShowRequestPermissionRationale(Activity activity, @NonNull String permission) {
        return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
    }

    /**
     * 权限申请统一入口
     * @param context
     * @param listener
     * @param permissions
     */
    public static void requestPermissions(Context context, PermissionTestListener listener, String... permissions) {
        String[] deniedPermission = checkSelPermissionStr(context, permissions);
        if (deniedPermission != null && deniedPermission.length > 0) {
            //优化:写个弹窗,告诉用户申请这些权限是用来做什么的(只提示没有授权的),当用户点击确定后再requestPermissionsStart,点击取消后可回调拒绝或不处理
            requestPermissionsStart(context, listener, deniedPermission);//送没有授权的权限
        } else {
            listener.onGranted(permissions);
        }
    }

    /**
     * 权限申请
     * @param context
     * @param listener
     * @param permissions
     */
    public static void requestPermissionsStart(Context context, final PermissionTestListener listener, final String... permissions) {
        //授权成功,拒绝,拒绝且不再询问的逻辑处理都由上层处理,则使用这个
//        PermissionTestHelp.getInstance().requestPermissionsStart(context,listener,permissions);

        /**
         *统一处理:拒绝且不再询问,弹窗引导用户去设置,用这个(推荐)
         * 那么修改传进来的Listener就不要用PermissionTestListener,换个**Listener
         * 上层只处理授权成功的业务那**Listener里面只实现onGranted方法
         * 处理授权成功和拒绝的业务**Listener里面实现onGranted、onDenied两个方法
         * 注:onDenied、onAskAgain某些情况会回都回调,申请多个权限ABCD,第一次我拒绝且不再询问权限A,后面拒绝BCD任何一个,
         * 所以上层一般不处理拒绝的回调,统一处理“拒绝且不再询问”后去引导用户设置
         */
        PermissionTestHelp.getInstance().requestPermissionsStart(context, new PermissionTestListener() {
            @Override
            public void onGranted(String[] grPermission) {
                LogUtil.i(TAG, "授权成功" + grPermission.length);
                listener.onGranted(grPermission);
            }

            @Override
            public void onDenied(List dePermissions) {
                LogUtil.i(TAG, "拒绝:" + dePermissions.size());
                listener.onDenied(dePermissions);
            }

            @Override
            public void onAskAgain(List asPermissions) {
                LogUtil.i(TAG, "拒绝且不再询问:" + asPermissions.size());
                //优化:弹窗提示用户需要什么权限(必须要开启,否者影响使用的这种权限),引导用户去设置开启
                listener.onAskAgain(asPermissions);
            }
        }, permissions);
    }
}

 三.PermissionTestHelp:用于跳转到透明activity类的

public class PermissionTestHelp {
    private static PermissionTestHelp permissionTestHelp = null;
    private PermissionTestListener listener;
    
    public synchronized static PermissionTestHelp getInstance() {
        if (permissionTestHelp == null) {
            permissionTestHelp = new PermissionTestHelp();
        }
        return permissionTestHelp;
    }

    //重点,后面透明activity就是通过这个方法得到listener进行回调
    public PermissionTestListener getListener() {
        return listener;
    }

 public void requestPermissionsStart(Context context, PermissionTestListener listener, String... permissions) {
        this.listener = listener;
        Intent intent = new Intent(context, PermissionTransparentActivity.class);
        intent.putExtra("permissions", permissions);
        context.startActivity(intent);
    }
}

 四.PermissionTransparentActivity透明的activity

/**
 * 透明的activity,用于发起权限申请,获得权限申请结果并回调到上层(因以下原因,所以才有这个activity)
 * 

* 权限申请结果必须在活动(activity/fragment)里面的获取的 * 非活动类implements ActivityCompat.OnRequestPermissionsResultCallback * 也不能在onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)里面获取权限申请的结果 */ public class PermissionTransparentActivity extends Activity { private int request_permissions_code = 1111; private String[] permissions; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); View view = new View(this); view.setBackgroundResource(R.color.tm);//透明背景 setContentView(view); Intent intent = getIntent(); if (intent != null) { permissions = intent.getStringArrayExtra("permissions"); if (null == permissions || 0 == permissions.length) { finish(); } } else { finish(); } if (!PermissionTestUtils.checkSelPermission(this, permissions)) {//没有获取到权限 ActivityCompat.requestPermissions(this, permissions, request_permissions_code); } else {//获取到权限了,那么直接关闭,若是不关闭就什么都点不了(尽量在上层获取到权限了都不用进来) finish(); } } /** * 请求权限结果 * * @param requestCode 请求的编码 * @param permissions 请求的权限String[] * @param grantResults 请求权限String[]一一对应的结果int[](0代表授权成功,-1代表授权失败) */ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == request_permissions_code) {//跟ActivityCompat.requestPermissions请求的requestCode要一致 PermissionTestListener listener = PermissionTestHelp.getInstance().getListener();//这样子获得回调 if (PermissionTestUtils.checkGrantResults(grantResults)) {//全部授权了 listener.onGranted(permissions);//回调回去 } else {//申请的权限没有全部被授权 // List grantedList = new ArrayList<>();//同意 List deniedList = new ArrayList<>();//拒绝 List askAgainList = new ArrayList<>();//拒绝且不再询问 for (String permission : permissions) { if (!PermissionTestUtils.checkSelPermission(this, permission)) {//没有授权 if (PermissionTestUtils.checkShouldShowRequestPermissionRationale(this, permission)) {//拒绝 deniedList.add(permission); } else {//拒绝且不再询问 askAgainList.add(permission); } }else { // grantedList.add(permission); } } // if (grantedList != null && grantedList.size() > 0) { // listener.onGranted(grantedList);//转成string[],这里只是同意部分权限, // } if (deniedList != null && deniedList.size() > 0) { listener.onDenied(deniedList); } if (askAgainList != null && askAgainList.size() > 0) { listener.onAskAgain(askAgainList); } } } finish(); } }

 五.补充color、AndroidManifest.xml(给activity静态注册)

color补充:    
#01000000

AndroidManifest.xml补充
  

 六.调用

    String[] permissionStr = new String[]{Manifest.permission.CAMERA,
            Manifest.permission.READ_PHONE_STATE};   

    PermissionTestUtils.requestPermissions(this, new PermissionTestListener() {
                @Override
                public void onGranted(String[] grPermission) {
                    Toast.makeText(PermissionTestActivity.this, "权限申请成功" + grPermission.length, Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onDenied(List dePermissions) {
                    Toast.makeText(PermissionTestActivity.this, "权限被拒绝" + dePermissions.size(), Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onAskAgain(List asPermissions) {
                    Toast.makeText(PermissionTestActivity.this, "权限被拒绝且不再询问,需要去设置开启" + asPermissions.size(), Toast.LENGTH_SHORT).show();
                }
            }, permissionStr);

七.优化:弹出提示用户申请的权限是干嘛用的;引导用户去设置开启权限时,需要告诉用户开启什么权限,比如下表格对应。

权限 权限名 权限干嘛用的
Manifest.permission.CAMERA 相机 自拍需要相机权限

结束:如有不足,请指正,谢谢!

你可能感兴趣的:(android,权限申请,权限申请带结果回调)