【问题标题】:Permission denied for window type 2038窗口类型 2038 的权限被拒绝
【发布时间】:2018-10-21 15:59:14
【问题描述】:

我正在修复一个不是我开发的 android 应用程序,几天前客户要求我将 targetSdkVersion 设置为 26(之前是 14),之后我注意到应用程序在某些情况下会崩溃,因为显示 ProgressDialog 时示例崩溃。这是出现此问题的代码部分:

mProgressDialog.setTitle(getString(R.string.downloading_data));
mProgressDialog.setMessage(mAlertMsg);
Drawable icon = getActivity().getDrawable(android.R.drawable.ic_dialog_info);
icon.setColorFilter(Color.parseColor("#00cbac"), PorterDuff.Mode.SRC_ATOP);
mProgressDialog.setIcon(icon);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setCancelable(false);
mProgressDialog.setButton(getString(R.string.cancel), loadingButtonListener);
mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
mProgressDialog.show();

执行最后一行的时候,app崩溃,Logcat中出现这个错误:

android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@b784d3a -- permission denied for window type 2003

当应用在搭载 Android 8 和 9 的设备上运行时会出现此问题。 我寻找类似问题的解决方案,我发现使用WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY而不是TYPE_SYSTEM_ALERT会更好,然后我修改了我在这篇文章中编写的代码的倒数第二行,但它没有改变任何东西,应用程序崩溃相同并且在日志中出现此错误:

android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@b784d3a -- permission denied for window type 2038

在清单中我有权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

我还从设备设置中启用了该应用的所有权限。 我该如何解决这个问题?

【问题讨论】:

  • 第二次崩溃发生在 Android 7 设备上,对吧?
  • 我尝试使用 Android 7 设备 (API 24),使用 TYPE_SYSTEM_ALERT 应用程序运行良好,而不是使用 TYPE_APPLICATION_OVERLAY 应用程序崩溃。如果我使用 API > 24 的设备,应用程序总是崩溃
  • 所以即使在 API 25+ 中使用 TYPE_APPLICATION_OVERLAY 也会崩溃?
  • 没错,我必须解决这个问题。
  • 您确定您已启用“在其他应用上绘制”权限?

标签: android android-windowmanager android-layoutparams


【解决方案1】:

如您所见,Android Oreo 及更高版本严重限制了您可以使用的覆盖类型。 Oreo 引入了新的 TYPE_APPLICATION_OVERLAY 常量供应用使用,同时弃用和禁止旧常量。

但是,TYPE_APPLICATION_OVERLAY 在 Nougat 及以下版本中不存在,因此尝试在那里使用它会导致 SecurityException。

替换

mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

有

mProgressDialog.getWindow().setType(
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
        else 
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);

至于为什么它仍然在使用TYPE_APPLICATION_OVERLAY 的 Oreo 及更高版本上崩溃,SYSTEM_ALERT_WINDOW 权限不是正常的运行时权限,并且不会显示在应用信息的“权限”部分下。它的面向用户的名称是“在其他应用程序上绘制”(通常),它位于通用应用程序信息页面或设置>>应用程序>>特殊访问权限下。

您不能像使用运行时权限那样以编程方式授予它,您可以通过一个简单的对话框来授予它。相反,您需要检查是否授予了权限,如果没有,请启动设置页面以允许用户授予它:How to programmatically grant the "draw over other apps" permission in android?


但是,我真的不明白为什么一个简单的进度对话框需要是一个完整的覆盖。事实上,ProgressDialog 已被完全弃用。您应该考虑迁移到一个简单的 ProgressBar,或者,如果您想保留 ProgressDialog,请删除 setType() 行。

【讨论】:

    猜你喜欢
    • 2018-02-22
    • 2023-02-09
    • 2018-01-18
    • 2019-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多