【问题标题】:Android: permission denied for window type 2038 using TYPE_APPLICATION_OVERLAYAndroid:使用 TYPE_APPLICATION_OVERLAY 的窗口类型 2038 的权限被拒绝
【发布时间】:2018-02-22 20:03:03
【问题描述】:

我试图创建一个高于其他应用程序的视图:

WindowManager.LayoutParams paramsDirectorView = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT);

我查看了其他回复,发现以下关于“绘制应用程序”的内容:

  • 我在清单中有 android.permission.SYSTEM_ALERT_WINDOW
  • 我正在做 Settings.canDrawOverlays(this) 检查 返回 true。
  • 我已经完成了这里permission denied for window type的所有工作

我仍然收到“-- 窗口类型 2038 的权限被拒绝”错误。到目前为止,我正在使用 TYPE_PHONE 并且它可以工作,但它已被弃用并说要使用 TYPE_APPLICATION_OVERLAY。有人可以跟进吗,因为 TYPE_PHONE 答案并不是真正的解决方案,而是 Android O 中已弃用的“补丁工作”解决方案。

我在 Android 7.1.2 上运行

android.view.WindowManager$BadTokenException: 无法添加窗口 android.view.ViewRootImpl$W@1f47e89 -- 窗口权限被拒绝 类型 2038 在 android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3344) 在 android.app.ActivityThread.-wrap21(ActivityThread.java) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1583) 在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:154) 在 android.app.ActivityThread.main(ActivityThread.java:6121) 在 java.lang.reflect.Method.invoke(Native Method) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779) 引起 作者:android.view.WindowManager$BadTokenException:无法添加窗口 android.view.ViewRootImpl$W@1f47e89 -- 窗口权限被拒绝 在 android.view.ViewRootImpl.setView(ViewRootImpl.java:703) 处输入 2038 在 android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:342) 在 android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93) 在 HeadService.TwoViewManager.(TwoViewManager.java:99) 在 HeadService.UIHeadService.onStartCommand(UIHeadService.java:65) 在 android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3327) 在 android.app.ActivityThread.-wrap21(ActivityThread.java) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1583) 在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:154) 在 android.app.ActivityThread.main(ActivityThread.java:6121) 在 java.lang.reflect.Method.invoke(Native Method) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)

【问题讨论】:

  • 只是好奇您是否找到了 TYPE_APPLICATION_OVERLAY 的实际解决方案?据我了解,下面的答案都没有真正解决这个问题。他们都在建议使用另一种 TYPE。
  • 正如公认的答案所描述的,您必须在奥利奥之前和之后考虑到,即您将使用两种类型。
  • 如果用户禁用“允许显示在其他应用程序上”可能会发生这种情况
  • @Derwrecked 任何其他原因,而不是permission 和您接受的答案。

标签: android android-windowmanager android-layoutparams


【解决方案1】:

我遇到了完全相同的问题。我想你应该区分目标(奥利奥之前和之后)

int LAYOUT_FLAG;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
     LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
        LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}

params = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        LAYOUT_FLAG,
        WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT);

【讨论】:

  • 我最终打算自己编写解决方案,但你成功了!
  • 如果我使用这个,我无法与覆盖的布局交互,还有其他方法吗
  • TYPE_PHONE 成功了。但是安装 .apk 文件时我无法获得安装按钮。有什么解决办法吗?
  • Life Saver 解决方案谢谢!!。花了两天时间后,我的应用终于可以工作了。
  • 我遵循相同的答案,但仍然在织物中崩溃
【解决方案2】:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

我在服务类中遇到了完全相同的问题(棉花糖之前和之后)。

if (Build.VERSION.SDK_INT >= 23) {
    if (!Settings.canDrawOverlays(this)) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
          Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, 1234);
    }
} else {
    startService(new Intent(SplashActivity.this,                     
    CheckServicesForApps.class));
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 1234) {
            startService(new Intent(SplashActivity.this, 
            CheckServicesForApps.class));

    }
}

public class CheckServicesForApps extends Service {
    private Context context = null;

    @Override
    public void onCreate() {
        super.onCreate();

        ImageView imageView = new ImageView(context);
        imageView.setVisibility(View.GONE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            try {
                windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);

                //here is all the science of params
                final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                        WindowManager.LayoutParams.WRAP_CONTENT,
                        WindowManager.LayoutParams.WRAP_CONTENT,
                        WindowManager. LayoutParams.TYPE_SYSTEM_ERROR,
                        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
                        PixelFormat.TRANSLUCENT
                );

                windowManager.addView(imageView, params);
                hand=new Handler();

            } catch (Exception e) {
                hand=new Handler();
                e.printStackTrace();
            }
        }else{
            windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

            final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.TYPE_PHONE,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                    PixelFormat.TRANSLUCENT);

            params.gravity = Gravity.TOP | Gravity.CENTER;
            params.x = ((getApplicationContext().getResources().getDisplayMetrics().widthPixels) / 2);
            params.y = ((getApplicationContext().getResources().getDisplayMetrics().heightPixels) / 2);
            windowManager.addView(imageView, params);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        /* We want this service to continue running until it is explicitly
        * stopped, so return sticky.
        */
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        if (imageView != null) {
            try {
                windowManager.removeView(imageView);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        /**** added to fix the bug of view not attached to window manager ****/
    }
}

【讨论】:

【解决方案3】:

您是否通过调用以下意图请求运行时权限?

private void requestOverlayPermission() {
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
        return;
    }

    Intent myIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
    myIntent.setData(Uri.parse("package:" + getPackageName()));
    startActivityForResult(myIntent, APP_PERMISSIONS);
}

然后在 onActivityResult() 中检查 Settings.canDrawOverlays(this) 是否为真,否则通过调用上述方法再次请求权限。

【讨论】:

  • 解决了我的问题,谢谢!
【解决方案4】:

Source SYSTEM_ALERT_WINDOW 字符串 SYSTEM_ALERT_WINDOW 允许应用使用 TYPE_APPLICATION_OVERLAY 类型创建窗口,显示在所有其他应用之上。很少有应用程序应该使用此权限;这些窗口旨在与用户进行系统级交互。

注意:如果应用面向 API 级别 23 或更高级别,则应用用户必须通过权限管理屏幕明确授予应用此权限。应用程序通过发送带有操作 ACTION_MANAGE_OVERLAY_PERMISSION 的意图来请求用户的批准。应用可以通过调用 Settings.canDrawOverlays() 来检查它是否有这个授权。

【讨论】:

    【解决方案5】:
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }else {
            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
    

    【讨论】:

      【解决方案6】:

      尝试将WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY 更改为WindowManager.LayoutParams.TYPE_PHONE

      【讨论】:

      • 感谢您的回复!然而,正如我在帖子中所说,我已经在使用它作为一种解决方法,但是这个 TYPE_PHONE 在 Android O 中已被弃用,我希望它最终能与 Android O 一起使用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-18
      • 2023-02-09
      • 2019-02-03
      • 1970-01-01
      • 1970-01-01
      • 2016-10-25
      • 1970-01-01
      相关资源
      最近更新 更多