Android WindowManager$BadTokenException权限问题求助(适配Oreo仍报错)
解决Android ViewRootImpl$W权限拒绝报错(WindowManager$BadTokenException)
问题回顾
你遇到的报错信息如下:
android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@c745883 - permission denied
对应的栈追踪:
01-30 15:11:41.037 13010-13010/project.app E/AndroidRuntime: FATAL EXCEPTION: main Process: project.app, PID: 13010 android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@c745883 -- permission denied for window type 2003 at android.view.ViewRootImpl.setView(ViewRootImpl.java:789) at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93) at android.app.Dialog.show(Dialog.java:330) at com.facebook.react.devsupport.DevSupportManagerImpl$4.run(DevSupportManagerImpl.java:344) at android.os.Handler.handleCallback(Handler.java:790) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6494) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
你已经意识到TYPE_SYSTEM_ERROR在Android 8.0+被弃用,替换为TYPE_APPLICATION_OVERLAY,但依然报错。
问题根源
Android 8.0(API 26)开始,TYPE_APPLICATION_OVERLAY对应的**SYSTEM_ALERT_WINDOW权限升级为特殊权限**——它不能像普通权限那样通过代码弹窗请求,必须引导用户到系统设置中手动开启。你的代码只替换了窗口类型,但没有完成权限的检查与申请流程,所以系统依然拒绝添加窗口。
解决方案
1. 声明权限
首先在AndroidManifest.xml中添加权限声明(即使是特殊权限,这一步也不能省略):
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
2. 检查并申请特殊权限
添加权限检查方法,引导用户到设置页面开启权限:
private void checkOverlayPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 判断是否已获取悬浮窗权限 if (!Settings.canDrawOverlays(this)) { // 跳转到系统设置页面,让用户开启权限 Intent overlayIntent = new Intent( Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()) ); startActivityForResult(overlayIntent, 1001); } else { // 已获取权限,执行窗口初始化逻辑 fixAndroid(); } } else { // Android 6.0以下无需特殊处理,直接执行 fixAndroid(); } }
3. 处理权限申请结果
重写onActivityResult方法,处理用户的权限选择:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1001) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOverlays(this)) { // 用户同意权限,执行窗口逻辑 fixAndroid(); } else { // 用户拒绝权限,给出提示 Toast.makeText(this, "需要开启悬浮窗权限才能正常使用调试功能", Toast.LENGTH_SHORT).show(); } } } }
4. 调整初始化流程
修改onCreate方法,先检查权限再执行窗口初始化:
@Override public void onCreate (Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 优先检查权限 checkOverlayPermission(); }
针对Expo Kit/React Native 0.48的额外说明
因为你的项目已经分离到Expo Kit,修改完上述代码后:
- 务必清理项目缓存(执行
./gradlew clean) - 在Android Studio中同步项目后再运行API 27的模拟器
- 这个报错来自React Native的调试支持类
DevSupportManagerImpl,说明调试弹窗需要悬浮窗权限,所以调试模式下必须确保权限已开启
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

