Android动态权限申请的优雅实现

前言

我们都知道从 Android 6.0(level 23)开始,应用权限都需要在运行时向用户申请授予权限,而不是像6.0以前只要在AndroidManifest.xml声明就会默认授予对应的权限。对于用户来说这样提高了隐私安全,但对于开发者来说,官方动态申请权限api比较繁杂(至少我自己感觉是这样的),而且几乎在每个需要用到权限的Activity都需要写一遍,费时不说,我们来探讨下如何才能更方便的实现吧。

我们先来看看官方获取动态权限的实现方式

这里以调起摄像头拍照举例说明

  1. 先在AndroidManifest.xml申明下拍照权限
<uses-permission android:name="android.permission.CAMERA" />
  1. 在需要使用到的Activity中实现下onRequestPermissionsResult方法,用于接收权限申请结果的回调
public class SampleActivity extends AppCompatActivity {

    private final int CAMERA_REQUEST = 8888;

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (grantResults != null && grantResults.length > 0) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                /*授予了权限,可调起摄像头拍照*/
                Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(intent, CAMERA_REQUEST);
            } else {
                /*无权限*/
                if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) {
                    /*false 选择了 Don’t ask again*/
                    /*拒绝权限且选择了不再询问,直接跳去设置页或弹窗提示*/

                } else {
                    /*拒绝权限但没选择不再询问*/
                    Toast.makeText(this, "您已拒绝拍照权限", Toast.LENGTH_LONG).show();
                }
            }
        }
    }
}
  1. 调用系统api申请拍照权限
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},CAMERA_REQUEST);

使用起来还算简单,但是如果我们很多个页面都需要动态申请权限,那么每个对应的Activity都需要覆写onRequestPermissionsResult方法,这样重复性的工作实在是太费时间了,所以,有没有方法可以方便得动态获取权限呢?当然有,这也是这篇文章要分享给大家的一种做法。

动态权限的推荐实现方式

实现方式多种多样,在这里我们采用Fragment辅助我们实现,利用Fragment拥有与Activity一样的生命周期和方法的特性,我们将onRequestPermissionsResult放在Fragment实现,具体实现细节如下:

  1. 单个权限申请
FragmentHelper.init(context).requestPermission(Manifest.permission.CAMERA, new FunctionFragment.OnSinglePermissionListener() {
                        @Override
                        public void onAccepted(FunctionFragment.Permission permission) {
                            if (permission.granted) {
                                /*允许拍照权限*/
                            } else {
                                if (!permission.shouldShowRequestPermissionRationale) {
                                    /*false 选择了 Don’t ask again*/
                                    /*拒绝权限且选择了不再询问*/
                                   
                                } else {
                                   /*拒绝权限但没选择不再询问*/
                                   Toast.makeText(this, "您已拒绝拍照权限", Toast.LENGTH_LONG).show();
                                }
                                
                            }
                        }
                    });
  1. 多个权限申请
FragmentHelper.init(this).requestPermissions(new String[]{
                Manifest.permission.CAMERA,
                Manifest.permission.ACCESS_COARSE_LOCATION
                }, new FunctionFragment.OnMultiPermissionListener() {
            @Override
            public void onAccepted(FunctionFragment.Permission[] permissions) {
                if (permissions != null && permissions.length > 0) {
                    /*允许和拒绝的逻辑跟单个权限申请一样,见上*/
                }
            }
        });
  1. 相关类

FunctionFragment

/**
 * 作者:lpx on 2020/4/14 17:24
 * Email : 1966353889@qq.com
 * Describe:功能Fragment(处理onActivityResult和onRequestPermissionsResult,如拍照和申请权限)
 */
public class FunctionFragment extends Fragment {
    private FragmentActivity mActivity;
    private Random mRandom = new Random();
    private SparseArray<OnBasePermissionListener> mPermissionCallbacks = new SparseArray<>();

    public FunctionFragment() {
    }

    public static FunctionFragment newInstance() {
        return new FunctionFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*设置为true,表示configuration change的时候,fragment实例不会被重新创建*/
        setRetainInstance(true);
        mActivity = getActivity();
    }

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

    /**
     * 申请权限(单个)
     *
     * @param needPermissionCheck 是否需要权限检查(申请权限前检查是否有权限,有则直接回调)
     */
    public void requestPermission(String permission, boolean needPermissionCheck, OnSinglePermissionListener listener) {
        int requestCode = getSoleRequestCode(TYPE.PERMISSIONS_RESULT);
        mPermissionCallbacks.put(requestCode, listener);
        /*先判断是否有权限,有直接回调(用户选择了仅使用期间允许时调requestPermissions会拉起系统授权弹窗,实际上已经有权限了)*/
        String[] permissions = new String[]{permission};
        if (needPermissionCheck && FragmentHelper.checkPermission(getContext(), permission)) {
            handlePermissionCallBack(requestCode, permissions, new int[]{PackageManager.PERMISSION_GRANTED});
        } else {
            requestPermissions(permissions, requestCode);
        }
    }

    /**
     * 申请权限(多个)
     *
     * @param needPermissionCheck 是否需要权限检查(申请权限前检查是否有权限,有则直接回调)
     */
    public void requestPermissions(String[] permissions, boolean needPermissionCheck, OnMultiPermissionListener listener) {
        int requestCode = getSoleRequestCode(TYPE.PERMISSIONS_RESULT);
        mPermissionCallbacks.put(requestCode, listener);
        if (needPermissionCheck) {
            /*先判断是否有权限,有直接回调(用户选择了仅使用期间允许时调requestPermissions会拉起系统授权弹窗,实际上已经有权限了)*/
            boolean isAllAllow = true;
            for (int i = 0, size = permissions.length; i < size; i++) {
                if (!FragmentHelper.checkPermission(getContext(), permissions[i])) {
                    isAllAllow = false;
                    break;
                }
            }
            if (isAllAllow) {
                int[] grantResults = new int[permissions.length];
                for (int i = 0, size = grantResults.length; i < size; i++) {
                    grantResults[i] = PackageManager.PERMISSION_GRANTED;
                }
                handlePermissionCallBack(requestCode, permissions, grantResults);
            } else {
                requestPermissions(permissions, requestCode);
            }
        } else {
            requestPermissions(permissions, requestCode);
        }
    }

    /**
     * 处理权限申请结果
     */
    private void handlePermissionCallBack(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        OnBasePermissionListener callback = mPermissionCallbacks.get(requestCode);
        if (callback == null) {
            return;
        }
        int length = grantResults.length;
        if (length == 0) {
            return;
        }
        mPermissionCallbacks.remove(requestCode);
        if (callback instanceof OnSinglePermissionListener) {
            int grantResult = grantResults[0];
            Permission permission;
            String name = permissions[0];
            if (grantResult == PackageManager.PERMISSION_GRANTED) {
                permission = new Permission(name, true);
            } else {
                if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, name)) {
                    permission = new Permission(name, false, true);
                } else {
                    permission = new Permission(name, false, false);
                }
            }
            ((OnSinglePermissionListener) callback).onAccepted(permission);
        } else if (callback instanceof OnMultiPermissionListener) {
            Permission[] array = new Permission[length];
            for (int i = 0; i < length; i++) {
                int grantResult = grantResults[i];
                Permission permission;
                String name = permissions[i];
                if (grantResult == PackageManager.PERMISSION_GRANTED) {
                    permission = new Permission(name, true);
                    array[i] = permission;
                } else {
                    if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, name)) {
                        permission = new Permission(name, false, true);
                    } else {
                        permission = new Permission(name, false, false);
                    }
                }
                array[i] = permission;
            }
            ((OnMultiPermissionListener) callback).onAccepted(array);
        }

    }

    /**
     * 获取唯一的requestCode,最多尝试10次
     */
    private int getSoleRequestCode(TYPE type) {
        int requestCode;
        int tryCount = 0;
        do {
            requestCode = mRandom.nextInt(0x0000FFFF);
            tryCount++;
        }
        while ((type == TYPE.ACTYVITY_RESILT ? mPhotoCallbacks.indexOfKey(requestCode) >= 0 : mPermissionCallbacks.indexOfKey(requestCode) >= 0) && tryCount < 10);
        return requestCode;
    }

    /**
     * 权限申请回调基础监听
     */
    public interface OnBasePermissionListener {
    }

    /**
     * 单个权限申请回调监听
     */
    public interface OnSinglePermissionListener extends OnBasePermissionListener {
        void onAccepted(Permission permission);
    }

    /**
     * 多个权限申请回调监听
     */
    public interface OnMultiPermissionListener extends OnBasePermissionListener {
        void onAccepted(Permission[] permission);
    }

    public enum TYPE {
        /**
         * 处理onActivityResult
         */
        ACTYVITY_RESILT,
        /**
         * 处理onRequestPermissionsResult
         */
        PERMISSIONS_RESULT
    }

    public static class Permission {
        /**
         * 权限名
         */
        public String name;
        /**
         * 是否允许授权
         */
        public boolean granted;
        /**
         * false 选择了 Don’t ask again
         */
        public boolean shouldShowRequestPermissionRationale;

        public Permission(String name, boolean granted) {
            this(name, granted, false);
        }

        public Permission(String name, boolean granted, boolean shouldShowRequestPermissionRationale) {
            this.name = name;
            this.granted = granted;
            this.shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale;
        }
    }
}

FragmentHelper

/**
 * 作者:lpx on 2020/4/14 14:39
 * Email : 1966353889@qq.com
 * Describe:辅助调起FunctionFragment
 */
public class FragmentHelper {
    private static final String TAG_PERMISSION = "TAG_FUNCTION_FRAGMENT";
    private FragmentActivity mActivity;

    private FragmentHelper(FragmentActivity mActivity) {
        this.mActivity = mActivity;
    }

    private FragmentHelper() {

    }

    /**
     * 返回FunctionFragment实例并与activity绑定
     */
    private FunctionFragment getFunctionFragment(FragmentActivity activity) {
        FunctionFragment fragment = (FunctionFragment) mActivity.getSupportFragmentManager().findFragmentByTag(TAG_PERMISSION);
        if (fragment == null) {
            fragment = FunctionFragment.newInstance();
            FragmentManager fragmentManager = activity.getSupportFragmentManager();
            fragmentManager
                    .beginTransaction()
                    .add(fragment, TAG_PERMISSION)
                    .commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return fragment;
    }

    /**
     * 返回FunctionFragment实例并与activity绑定
     */
    private FunctionFragment getFunctionFragment(FragmentManager fragmentManager) {
        FunctionFragment fragment = (FunctionFragment) fragmentManager.findFragmentByTag(TAG_PERMISSION);
        if (fragment == null) {
            fragment = FunctionFragment.newInstance();
            fragmentManager
                    .beginTransaction()
                    .add(fragment, TAG_PERMISSION)
                    .commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return fragment;
    }

    /**
     * 申请权限(多个)
     *
     * @param needPermissionCheck 是否需要权限检查(申请权限前检查是否有权限,有则直接回调)
     */
    public void requestPermissions(String[] permissions, boolean needPermissionCheck, FunctionFragment.OnMultiPermissionListener listener) {
        getFunctionFragment(mActivity).requestPermissions(permissions, needPermissionCheck, listener);
    }

    /**
     * 申请权限(单个)
     *
     * @param needPermissionCheck 是否需要权限检查(申请权限前检查是否有权限,有则直接回调)
     */
    public void requestPermission(String permission, boolean needPermissionCheck, FunctionFragment.OnSinglePermissionListener listener) {
        getFunctionFragment(mActivity).requestPermission(permission, needPermissionCheck, listener);
    }

    /**
     * 申请权限(多个)
     *
     * @param needPermissionCheck 是否需要权限检查(申请权限前检查是否有权限,有则直接回调)
     */
    public void requestPermissions(FragmentManager fragmentManager, String[] permissions, boolean needPermissionCheck, FunctionFragment.OnMultiPermissionListener listener) {
        getFunctionFragment(fragmentManager).requestPermissions(permissions, needPermissionCheck, listener);
    }

    /**
     * 申请权限(单个)
     *
     * @param needPermissionCheck 是否需要权限检查(申请权限前检查是否有权限,有则直接回调)
     */
    public void requestPermission(FragmentManager fragmentManager, String permission, boolean needPermissionCheck, FunctionFragment.OnSinglePermissionListener listener) {
        getFunctionFragment(fragmentManager).requestPermission(permission, needPermissionCheck, listener);
    }

    /**
     * 申请权限(多个)
     */
    public void requestPermissions(String[] permissions, FunctionFragment.OnMultiPermissionListener listener) {
        getFunctionFragment(mActivity).requestPermissions(permissions, false, listener);
    }

    /**
     * 申请权限(单个)
     */
    public void requestPermission(String permission, FunctionFragment.OnSinglePermissionListener listener) {
        getFunctionFragment(mActivity).requestPermission(permission, false, listener);
    }

    /**
     * 申请权限(多个)
     */
    public void requestPermissions(FragmentManager fragmentManager, String[] permissions, FunctionFragment.OnMultiPermissionListener listener) {
        getFunctionFragment(fragmentManager).requestPermissions(permissions, false, listener);
    }

    /**
     * 申请权限(单个)
     */
    public void requestPermission(FragmentManager fragmentManager, String permission, FunctionFragment.OnSinglePermissionListener listener) {
        getFunctionFragment(fragmentManager).requestPermission(permission, false, listener);
    }

    /**
     * 初始化返回Activity对应绑定的FunctionFragment实例
     */
    public static FragmentHelper init(FragmentActivity fragmentActivity) {
        return new FragmentHelper(fragmentActivity);
    }

    /**
     * 初始化返回Activity对应绑定的FunctionFragment实例
     */
    public static FragmentHelper init() {
        return new FragmentHelper();
    }

    /**
     * 检查权限
     */
    public static boolean checkPermission(Context context, @NonNull String permission) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return true;
        } else {
            return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
        }
    }
}

怎么样,是不是这样就方便很多了,只要在需要动态申请权限的地方通过FragmentHelper调下就可以了,

结尾

希望本文可以帮助到您,也希望各位不吝赐教,提出您在使用中的宝贵意见,谢谢。
如果可以的话,也可以扫一扫下方的二维码请作者喝一杯奶茶哈
在这里插入图片描述
谢谢您的观看。
有问题可发送至:1966353889@qq.com
欢迎交流,共同进步。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值