Android用户权限之记录是否调起弹窗

Android用户权限之记录是否调起弹窗

记录一个最近在开发中遇到的奇葩需求,需求内容主要是:

记录在申请权限的时候客户端的行为,包括是否弹出了系统权限,以及弹出情况下用户是否同意授权

对于是否弹窗,我们都知道Android权限的几种情况:

  1. 设置中处于询问的状态(初次请求权限或者已拒绝权限但没有点击不再提示(也有部分手机拒绝了就不再提示)或者手动到设置中设置),这种会弹出权限申请框
  2. 设置中处于同意的状态,不弹起申请框直接通过申请
  3. 设置中处于拒绝的状态,不弹起申请框直接拒绝申请

我们回过头看一下需求,弹出的情况下用户是否同意授权这个其实很好判断,主要是是否弹出了授权框,我们通过系统的api并不能直接拿到这个结果。因为弹出申请框是一个系统行为,并不是我们自己定义的一个弹框。

我们可以先回顾一下申请权限的原始步骤:

requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 100);

然后在回调中处理申请结果:

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

客户端做的事情起其实只有

  1. 发起申请权限的动作
  2. 处理申请权限的结果
    对于整个申请过程都是透明的,客户端并不知道是否有弹窗

所以我们这里只有曲线救国了,我们分析一下现在有的几种可能性:

  1. 第一次申请权限(包括手动修改设置为询问状态)
  2. 已拒绝但是没有点击不再显示
  3. 已拒绝也已点击不再显示
  4. 已通过授权

这里第1,2两种情况是会发起授权的,34两种情况不会再发起授权,所以我们的重点在于如何区分这四种状态。

第四种很好区分,通过ContextCompat.checkSelfPermission()方法就可以检测出
这里介绍一下另一个方法:

ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission)

这个方法返回一个boolean值,表示之前是否已经被拒绝过但是还没有点击不再显示。所以通过这个方法可以区分出来第二种情况。

那我们就剩下第一种和第三种如何区分了,第一种的话其实我们可以发现有一个规律,第一次去请求权限是肯定不会有不再显示按钮的,包括重新将状态设置为询问,这个大家可以测试一下。

所以我们可以根据请求结果做一下文章

请求结果是成功的

这种肯定就是第一种情况,因为如果是第三种情况是肯定不会请求成功的(第二种和第四种在请求结果之前就已经筛选出去了,所以不用考虑)

请求结果失败

这里就可以再次用上这个方法了

ActivityCompat.shouldShowRequestPermissionRationale

如果是第一种情况,那么这个方法应该是返回true,因为第一次是没有不再显示这个按钮的,如果返回false那么就是第三种情况,这样就区分出来了

经过这个需求只能说对于权限系统理解更深了吧。
/(ㄒoㄒ)/~~

附上代码:
定义一个enum表示上面的四种状态

public enum PermissionState{
    /**
     * 询问状态,展示弹窗
     */
    ASKING(true),
    /**
     * 点击拒绝,未点击不再显示,展示弹窗
     */
    MORE_REQUEST(true),
    /**
     * 已同意,不展示弹窗
     */
    HAS_GRANTED(false),
    /**
     * 点击拒绝,已点击不再显示,不展示弹窗
     */
    DEFINED(false);

    private boolean mShowDialog;

    PermissionState(boolean showDialog){
        mShowDialog = showDialog;
    }

    public boolean isShowDialog(){
        return mShowDialog;
    }
}

定义一个结果接收权限申请结果:

public interface PermissionListener {
    void onSucceed(int var1, @NonNull List<String> var2);

    void onFailed(int var1, @NonNull List<String> var2);
}

新增一个装饰类处理结果进行区分:

public class PermissionTrackerListener implements PermissionListener {
    private Activity mActivity;
    private PermissionListener mListener;
    /**
     * 权限列表
     */
    private List<String> mNeedTrackPermissionList;
    /**
     * 当前几个权限的状态
     */
    private List<PermissionState> mNeedTrackPermissionStateList;

    public PermissionTrackerListener(Activity activity, PermissionListener listener){
        mActivity = activity;
        mListener = listener;
        mNeedTrackPermissionList = new ArrayList<>();
        mNeedTrackPermissionStateList = new ArrayList<>();
    }

    @Override
    public void onSucceed(int i, @NonNull List<String> list) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (int j = 0; j < mNeedTrackPermissionList.size(); j++) {
                PermissionState state = mNeedTrackPermissionStateList.get(j);
                String permission = mNeedTrackPermissionList.get(j);
                if (state == null){
                    state = PermissionState.ASKING;
                }
                if (state == PermissionState.ASKING || state == PermissionState.MORE_REQUEST) {
                    Toast.makeText(mActivity, "已弹窗埋点: " + permission, Toast.LENGTH_SHORT).show();
                    Toast.makeText(mActivity, "点击同意埋点: " + permission, Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(mActivity, "未弹窗埋点: " + permission, Toast.LENGTH_SHORT).show();
                }
            }
        }
        mListener.onSucceed(i, list);
    }

    @Override
    public void onFailed(int i, @NonNull List<String> list) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (int j = 0; j < mNeedTrackPermissionList.size(); j++) {
                String permission = mNeedTrackPermissionList.get(j);
                boolean denied = list.contains(permission);
                PermissionState state = mNeedTrackPermissionStateList.get(j);
                if (state == null) {
                    if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, permission)) {
                        state = PermissionState.ASKING;
                    } else {
                        state = PermissionState.DEFINED;
                    }
                }
                if (state == PermissionState.ASKING || state == PermissionState.MORE_REQUEST) {
                    Toast.makeText(mActivity, "已弹窗埋点: " + permission, Toast.LENGTH_SHORT).show();
                    if (denied) {
                        Toast.makeText(mActivity, "点击拒绝埋点: " + permission, Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(mActivity, "点击同意埋点: " + permission, Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(mActivity, "未弹窗埋点: " + permission, Toast.LENGTH_SHORT).show();
                }
            }
        }
        mListener.onFailed(i, list);
    }

    /**
     * 申请权限之前调用
     * @param list  需要申请的权限
     */
    public void preRequestPermission(@NonNull List<String> list){
        mNeedTrackPermissionList = list;
        if (mNeedTrackPermissionList.isEmpty()){
            return;
        }
        for (String permission : mNeedTrackPermissionList) {
            PermissionState state = null;
            if (ActivityCompat.checkSelfPermission(mActivity, permission) == PackageManager.PERMISSION_GRANTED){
                state = PermissionState.HAS_GRANTED;
            } else if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, permission)){
                state = PermissionState.MORE_REQUEST;
            }
            mNeedTrackPermissionStateList.add(state);
        }
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值