Android用户权限之记录是否调起弹窗
Android用户权限之记录是否调起弹窗
记录一个最近在开发中遇到的奇葩需求,需求内容主要是:
记录在申请权限的时候客户端的行为,包括是否弹出了系统权限,以及弹出情况下用户是否同意授权
对于是否弹窗,我们都知道Android权限的几种情况:
- 设置中处于询问的状态(初次请求权限或者已拒绝权限但没有点击不再提示(也有部分手机拒绝了就不再提示)或者手动到设置中设置),这种会弹出权限申请框
- 设置中处于同意的状态,不弹起申请框直接通过申请
- 设置中处于拒绝的状态,不弹起申请框直接拒绝申请
我们回过头看一下需求,弹出的情况下用户是否同意授权这个其实很好判断,主要是是否弹出了授权框,我们通过系统的api并不能直接拿到这个结果。因为弹出申请框是一个系统行为,并不是我们自己定义的一个弹框。
我们可以先回顾一下申请权限的原始步骤:
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 100);
然后在回调中处理申请结果:
@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { }
客户端做的事情起其实只有
- 发起申请权限的动作
- 处理申请权限的结果
对于整个申请过程都是透明的,客户端并不知道是否有弹窗
所以我们这里只有曲线救国了,我们分析一下现在有的几种可能性:
- 第一次申请权限(包括手动修改设置为询问状态)
- 已拒绝但是没有点击不再显示
- 已拒绝也已点击不再显示
- 已通过授权
这里第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 var2); void onFailed(int var1, @NonNull List var2);}
新增一个装饰类处理结果进行区分:
public class PermissionTrackerListener implements PermissionListener { private Activity mActivity; private PermissionListener mListener; /** * 权限列表 */ private List mNeedTrackPermissionList; /** * 当前几个权限的状态 */ private List 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 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 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 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); }}}
更多相关文章
- Ubuntu上开发Android,手机调试配置
- Android中使用Notification并通过点击Notification启动启动通知
- Android实现通过浏览器点击链接打开本地应用(APP)并拿到浏览器传递
- Android(安卓)录制手机屏幕视频生成GIF图片实例详解
- 用android做的一个简单的电话拨号器的错误的解决(用android模拟两
- 安卓TV开发(九) Android模拟事件 遥控器变身成鼠标来操作TV
- android 验证码按钮点击,判断网络和匹配手机号并自动更新时间;
- android 事件分发,解决由于listview中实时刷新,导致子view点击事件
- Android跨程序共享数据