做一个应用Log的实时显示,发现需要用到
SYSTEM_ALERT_WINDOW权限,视同通用方式获取后发现并不行。
普通权限获取流程
我们在项目中采用的是PermissionsDispatcher,使用方式也很简单,只需要在类上注解@RuntimePermissions ,写一个public void的方法,例如initAfterPermissionChecked,此方法中写权限获取后的操作即可,方法上用@NeedsPermission(Manifest.permission.CAMERA)注解即可,多个权限可以写成下面的形式
1 |
编译代码后自动生成类名 + PermissionsDispatcher的Java文件,例如LaunchActivityPermissionsDispatcher,在需要获取权限的地方直接调用方法名 + WithPermissionCheck(this); 生成的Java文件中已经给你生成好了这个方法,例如initAfterPermissionCheckedWithPermissionCheck(),其他针对各种授权与否的处理就不细说了。
问题
对于SYSTEM_ALERT_WINDOW权限,我本想采用相同的方法处理,直接在权限列表后加入Manifest.permission.SYSTEM_ALERT_WINDOW,结果编译后直接报错
1 | Method 'initAfterPermissionChecked()' defines 'android.permission.SYSTEM_ALERT_WINDOW' with other permissions at the same time. |
根据这个issues

大概意思就是WRITE_SETTINGS和SYSTEM_ALERT_WINDOW这类权限不能作为普通权限申请流程的一部分一起申请,因为我们一般需要重新跳转到设置界面去授予权限。
解决
在新的类中获取SYSTEM_ALERT_WINDOW权限,同样的流程,类名上注解@RuntimePermissions ,新建public void 方法并注解@NeedsPermission(Manifest.permission.SYSTEM_ALERT_WINDOW),这里我写的是
1 |
|
获取权限到地方直接用的
1 | LoginActivityPermissionsDispatcher.checkSystemAlertPermissionWithPermissionCheck(this); |
获取。编译运行后发现存在一个问题,那就是这个权限会直接跳转到设置界面,我们需要给个Dialog让用户选择
1 | new AlertDialog.Builder(this) |
我们同样不能再进入的时候每次都弹窗让用户选择,毕竟该权限可能已经授予了。于是我选择了使用ContextCompat或者PermissionChecker的checkSelfPermission()方法来校验当前权限是否获取到,但是每次获取的值都是PackageManager.PERMISSION_DENIED,于是我们采用另一种方法去获取权限是否授予
1 | Settings.canDrawOverlays(this) |
方法注释如下

至此,我们就能正常获取SYSTEM_ALERT_WINDOW权限了
1 | if (!Settings.canDrawOverlays(this)) { |