Android6.0开启悬浮窗的解决方案| permission denied for window type 2003 , 2038

        Android6.0 实现一个悬浮窗的功能,解决方案有两种:

        一是如果你做的是系统应用开发,只要给apk签名,那么默认悬浮窗权限是给予的,显然这种情况不符合大多数开发者的要求;

        二是在开启悬浮窗之前,引导用户去开启权限 : 权限开启的UI路径是 “ 通用 -- 应用管理 -- 更多 -- 配置应用 --- 在其他应用的上层显示 --- 选择你的APP -- 运行在其他应用的上层显示 ”;

        做系统悬浮窗需要申请权限,6.0以上的 还需要动态申请下的,以下为动态权限的申请:

【步骤1】在AndroidManifest.xml中添加悬浮窗的权限

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

【步骤2】悬浮窗的权限申请

public static int OVERLAY_PERMISSION_REQ_CODE = 1234;

private void checkAndRequestPermissions() {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M 
                        && !Settings.canDrawOverlays(this)){
            Intent intent = 
                 new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                            Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent,OVERLAY_PERMISSION_REQ_CODE);
        }else {
            //todo 正常逻辑
        }
    }

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onActivityResult(int requestCode, int resultCode, @org.jetbrains.annotations.Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == OVERLAY_PERMISSION_REQ_CODE){
            if(!Settings.canDrawOverlays(this)){
                ToastUtil.showShort("权限授予失败,无法开启悬浮窗");
            }else {
                ToastUtil.showShort("权限授予成功,开启悬浮窗");
                //todo正常逻辑
            }
        }
    }

 方法checkAndRequestPermissions() 可引导用户开机悬浮窗权限;

但是,在申请完权限后仍然不行,运行时会出现"permission denied for window type 2003" 的权限拒绝的提示,这里主要是出现在了这个类型的设置上,上边代码是错误的,也就是TYPE_SYSTEM_ALERT因为这个被遗弃了,不赞成使用,进去后看到,让使用 TYPE_APPLICATION_OVERLAY;因此我们需要根据不同版本使用不同代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){//6.0
    wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else {
    wmParams.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
}

 代码如下:

    private void createFloatView() {
        wmParams = new WindowManager.LayoutParams();
        //获取WindowManagerImpl.CompatModeWrapper
        mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE);
        //设置window type
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){//6.0+
            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }else {
            wmParams.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }
//        wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        //设置图片格式,效果为背景透明
        wmParams.format = PixelFormat.RGBA_8888;
        //设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
        wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

        //调整悬浮窗显示的停靠位置为左侧置顶
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;

        // 以屏幕左上角为原点,设置x、y初始值
        wmParams.x = 1180;
        wmParams.y = ViewUtil.oriPxToTarPx(200);

        //设置悬浮窗口长宽数据
        wmParams.width = ViewUtil.oriPxToTarPx(100);
        wmParams.height = ViewUtil.oriPxToTarPx(100);

        LayoutInflater inflater = LayoutInflater.from(getApplication());
        //获取浮动窗口视图所在布局
        
        mFloatLayout = (FrameLayout) inflater.inflate(R.layout.service_suspend, null);
        mFloatLayout.setElevation(10F);
        //添加mFloatLayout
        mWindowManager.addView(mFloatLayout, wmParams);

        //浮动窗口按钮
        mFloatView = (ImageView) mFloatLayout.findViewById(R.id.image_suspend_service);
       
        mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
                .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        //设置监听浮动窗口的触摸移动
        mFloatView.setOnTouchListener(new View.OnTouchListener() {
            int x = 0;
            int y = 0;
            private boolean isMoving = false;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                int newX = (int) event.getRawX() - mFloatView.getMeasuredWidth() / 2;
                int newY = (int) event.getRawY() - mFloatView.getMeasuredHeight() / 2;

                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        isMoving = false;
                        x = (int) event.getRawX() - mFloatView.getMeasuredWidth() / 2;
                        y = (int) event.getRawY() - mFloatView.getMeasuredHeight() / 2 - getStatusBarHeight();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (Math.sqrt((double) (newX - x) * (double) (newX - x) + (double) (newY - y) * (double) (newY - y)) > ViewUtil.oriPxToTarPx(36) || isMoving) {
                            isMoving = true;
                            wmParams.x = newX;
                            wmParams.y = newY;
                            mWindowManager.updateViewLayout(mFloatLayout, wmParams);
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        if (Math.sqrt((double) (newX - x) * (double) (newX - x) + (double) (newY - y) * (double) (newY - y)) <= ViewUtil.oriPxToTarPx(36)) {
                            isMoving = false;
                            //逻辑处理
                        }
                        break;
                    default:
                        break;
                }
                return true;
            }
        });
    }

 add:

当时用的设备是9.0的,没问题,可以运行,之后开发,7.0,6.0以下版本的终端上会崩溃,会报异常permission denied for window type 2038,   经过多个实验发现这个权限

wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

只能在安卓版本7.1之上的版本才能有效,所以可以修改一下判断:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1){//7.1+
            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }else {
            wmParams.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }

以上,只是修改了一个版本的判断,然后就可以继续运行了;

以上仅供参考;

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值