Android无法解决permission denied for this window type

Android 中无法解决 Permission Denied for this Window Type 错误的详细解决方案

Permission Denied for this Window Type 是 Android 开发中一个常见的权限问题,通常出现在尝试在应用中使用特定类型的窗口或界面时。以下是对该问题的详细解释、解决方案以及示例代码。

1. 问题描述

在 Android 应用中,Permission Denied for this Window Type 错误通常发生在尝试创建或显示窗口(如 DialogPopupWindowWindowManager 的自定义窗口)时,当前应用没有足够的权限来执行这些操作。

错误信息示例

plaintext
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?

常见场景

  • 使用 WindowManager 添加窗口或视图时。
  • 尝试创建系统级窗口(例如悬浮窗)时。

2. 解决方案

2.1 检查和添加必要的权限

不同类型的窗口需要不同的权限。常见的权限包括:

  • 悬浮窗权限

    对于需要创建悬浮窗的应用,您需要在 AndroidManifest.xml 文件中添加以下权限:

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

    从 Android 6.0(API 级别 23)开始,您还需要在运行时请求该权限:

    java
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(context)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName())); startActivityForResult(intent, REQUEST_CODE); } }
  • TYPE_APPLICATION_OVERLAY 权限

    从 Android 8.0(API 级别 26)开始,SYSTEM_ALERT_WINDOW 权限被分为 TYPE_APPLICATION_OVERLAY。更新后的权限声明如下:

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

    使用 TYPE_APPLICATION_OVERLAY

    java
    WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, // API 26 及以上使用此类型 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);

2.2 检查窗口类型

在创建窗口时,确保使用了正确的窗口类型。以下是一些常见窗口类型及其用途:

  • TYPE_APPLICATION:应用窗口。
  • TYPE_APPLICATION_PANEL:应用面板窗口。
  • TYPE_SYSTEM_ALERT:系统级警报窗口(Android 8.0 后被 TYPE_APPLICATION_OVERLAY 替代)。
  • TYPE_APPLICATION_OVERLAY:用于创建悬浮窗(API 26 及以上)。

示例代码:设置悬浮窗

java
public class MyService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { 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, REQUEST_CODE); } else { showOverlay(); } } else { showOverlay(); } return START_NOT_STICKY; } private void showOverlay() { WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, // API 26 及以上使用此类型 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); View overlayView = LayoutInflater.from(this).inflate(R.layout.overlay_layout, null); windowManager.addView(overlayView, params); } @Override public IBinder onBind(Intent intent) { return null; } }

2.3 确保 Activity 处于运行状态

确保在进行窗口操作时,Activity 是处于运行状态的。如果 Activity 被销毁或不是前台状态,窗口操作可能会失败。

2.4 检查 WindowManager 设置

确保 WindowManagerLayoutParams 设置正确,特别是 typeflags

java
WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, // 适用于 Android 8.0 及以上 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT );

3. 常见问题与解决方案

3.1 问题:Permission Denied 错误

原因:应用缺少必要的权限或权限请求未被批准。

解决方案

  • 确保 AndroidManifest.xml 中声明了正确的权限。
  • 对于 Android 6.0 及以上版本,确保在运行时请求了 SYSTEM_ALERT_WINDOW 权限。

3.2 问题:窗口类型不正确

原因:使用了不适合的窗口类型。

解决方案

  • 对于系统级窗口,使用 TYPE_APPLICATION_OVERLAY
  • 确保 TYPE_APPLICATION_OVERLAY 是正确的类型。

3.3 问题:Activity 不在前台

原因:尝试在 Activity 不在前台时创建窗口。

解决方案

  • 确保 Activity 处于活动状态,或考虑将窗口创建逻辑移至 Service 中。

4. 完整示例代码

以下是一个示例,展示如何在 Android 中处理 Permission Denied for this Window Type 错误:

java
public class MyOverlayService extends Service { private static final int REQUEST_CODE = 1234; @Override public int onStartCommand(Intent intent, int flags, int startId) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOverlays(this)) { showOverlay(); } else { Intent overlayIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(overlayIntent, REQUEST_CODE); } } else { showOverlay(); } return START_NOT_STICKY; } private void showOverlay() { WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, // API 26 及以上使用此类型 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT ); View overlayView = LayoutInflater.from(this).inflate(R.layout.overlay_layout, null); windowManager.addView(overlayView, params); } @Override public IBinder onBind(Intent intent) { return null; } }

5. 参考资料

总结与关键字

总结

在 Android 开发中处理 Permission Denied for this Window Type 错误主要涉及到检查和请求适当的权限、确保使用正确的窗口类型以及验证 Activity 的状态。解决方案包括在 AndroidManifest.xml 中添加权限声明,动态请求权限,确保 WindowManager 设置正确,以及处理运行时权限问题。示例代码展示了如何处理这些问题,并提供了处理悬浮窗的完整实现。

关键字

Android, Permission Denied for this Window Type, WindowManager, SYSTEM_ALERT_WINDOW, TYPE_APPLICATION_OVERLAY, 权限问题, `AndroidMan