做一个应用 Log 的实时显示,发现需要用到 SYSTEM_ALERT_WINDOW 权限,视同通用方式获取后发现并不行。

# 普通权限获取流程

我们在项目中采用的是 PermissionsDispatcher, 使用方式也很简单,只需要在类上注解 @RuntimePermissions , 写一个 public void 的方法,例如 initAfterPermissionChecked , 此方法中写权限获取后的操作即可,方法上用 @NeedsPermission(Manifest.permission.CAMERA) 注解即可,多个权限可以写成下面的形式

@NeedsPermission({Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION})

编译代码后自动生成 类名 + PermissionsDispatcher 的 Java 文件,例如 LaunchActivityPermissionsDispatcher , 在需要获取权限的地方直接调用 方法名 + WithPermissionCheck(this); 生成的 Java 文件中已经给你生成好了这个方法,例如 initAfterPermissionCheckedWithPermissionCheck() , 其他针对各种授权与否的处理就不细说了。

# 问题

对于 SYSTEM_ALERT_WINDOW 权限,我本想采用相同的方法处理,直接在权限列表后加入 Manifest.permission.SYSTEM_ALERT_WINDOW ,结果编译后直接报错

Method 'initAfterPermissionChecked()' defines 'android.permission.SYSTEM_ALERT_WINDOW' with other permissions at the same time.

根据这个 issues

大概意思就是 WRITE_SETTINGSSYSTEM_ALERT_WINDOW 这类权限不能作为普通权限申请流程的一部分一起申请,因为我们一般需要重新跳转到设置界面去授予权限。

# 解决

在新的类中获取 SYSTEM_ALERT_WINDOW 权限,同样的流程,类名上注解 @RuntimePermissions ,新建 public void 方法并注解 @NeedsPermission(Manifest.permission.SYSTEM_ALERT_WINDOW) ,这里我写的是

@NeedsPermission(Manifest.permission.SYSTEM_ALERT_WINDOW)
    public void checkSystemAlertPermission(){
    }

获取权限到地方直接用的

LoginActivityPermissionsDispatcher.checkSystemAlertPermissionWithPermissionCheck(this);

获取。编译运行后发现存在一个问题,那就是这个权限会直接跳转到设置界面,我们需要给个 Dialog 让用户选择

new AlertDialog.Builder(this)
                    .setTitle("提示")
                    .setMessage("显示Log需要在设置中打开系统悬浮窗权限,是否打开?")
                    .setPositiveButton("确定", (dialog, which) -> {
                        LoginActivityPermissionsDispatcher.checkSystemAlertPermissionWithPermissionCheck(this);
                        dialog.dismiss();
                    })
                    .setNegativeButton("取消", (dialog, which) -> {
                        dialog.dismiss();
                    })
                    .show();

我们同样不能再进入的时候每次都弹窗让用户选择,毕竟该权限可能已经授予了。于是我选择了使用 ContextCompat 或者 PermissionCheckercheckSelfPermission() 方法来校验当前权限是否获取到,但是每次获取的值都是 PackageManager.PERMISSION_DENIED , 于是我们采用另一种方法去获取权限是否授予

Settings.canDrawOverlays(this)

方法注释如下

至此,我们就能正常获取 SYSTEM_ALERT_WINDOW 权限了

if (!Settings.canDrawOverlays(this)) {
            new AlertDialog.Builder(this)
                    .setTitle("提示")
                    .setMessage("显示Log需要在设置中打开系统悬浮窗权限,是否打开?")
                    .setPositiveButton("确定", (dialog, which) -> {
                        LoginActivityPermissionsDispatcher.checkSystemAlertPermissionWithPermissionCheck(this);
                        dialog.dismiss();
                    })
                    .setNegativeButton("取消", (dialog, which) -> {
                        dialog.dismiss();
                    })
                    .show();
        }
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Logan 微信支付

微信支付

Logan 支付宝

支付宝

Logan 贝宝

贝宝