无论标记与绘制权限,仍遇Window Type 2038权限拒绝崩溃求助
问题描述
已知该问题被多次提问,但仍收到不同API目标版本用户的崩溃报告。我有一个前台服务,每次运行前都会检查绘制权限,相关代码如下:
int flags; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { flags = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { flags = WindowManager.LayoutParams.TYPE_PHONE; } myWindowParams = new WindowManager.LayoutParams( movable_width, movable_height, flags, WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, PixelFormat.TRANSLUCENT);
Manifest配置:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Firebase捕获的错误信息:
Exception: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@1a0fb9e -- permission denied for window type 2038 at android.view.ViewRootImpl.setView(ViewRootImpl.java:830) at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94) at com.b.app.mainService.setupWindows(mainService.java:26) at android.app.ActivityThread.handleCreateService(ActivityThread.java:3544) at android.app.ActivityThread.access$1300(ActivityThread.java:200) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1676) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6762) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
求解决思路。
解决思路
严格校验权限有效性:
不要仅依赖Manifest声明,每次添加窗口前必须主动校验权限:- API 23+:用
Settings.canDrawOverlays(context)判断悬浮窗权限状态; - API <23:虽然
SYSTEM_ALERT_WINDOW是正常权限,但部分定制ROM可能有限制,需用checkSelfPermission确认;
未获取权限时,引导用户跳转到系统设置开启:
if (!Settings.canDrawOverlays(context)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName())); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); // 暂停服务或提示用户,待权限开启后再执行窗口逻辑 return; }- API 23+:用
修正窗口类型的版本兼容逻辑:
错误中的窗口类型2038对应TYPE_APPLICATION_OVERLAY,部分Android 8.0/8.1定制ROM可能存在权限异常。可在权限校验通过后,若仍触发崩溃,尝试降级使用TYPE_PHONE(需注意部分ROM对该类型也有管控)。延迟服务内的窗口添加操作:
服务启动初期(onCreate/onStartCommand)系统环境可能未完全就绪,建议通过Handler.postDelayed延迟窗口添加逻辑,避免因系统状态不稳定导致权限校验失效。捕获权限动态回收的异常:
用户可能在应用运行时手动关闭悬浮窗权限,此时添加窗口会崩溃。需在添加窗口的代码块外层包裹try-catch,捕获WindowManager.BadTokenException,并在异常处理中重新引导用户开启权限或停止相关逻辑:try { windowManager.addView(yourView, myWindowParams); } catch (WindowManager.BadTokenException e) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName())); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); // 停止当前窗口相关逻辑 }适配定制ROM的特殊限制:
小米、华为、OPPO等国产ROM对悬浮窗权限有更严格的管控,部分需要单独申请ROM专属的“显示悬浮窗”权限。可针对这些品牌设备,添加对应的权限引导逻辑,跳转到品牌专属的权限设置页面。
内容的提问来源于stack exchange,提问作者Bialy
相关产品推荐
相关产品推荐

