您的位置:首页 > 移动开发 > Android开发

Android 6.0 悬浮窗默认关闭解决方案

2016-04-20 18:24 495 查看
#Android 6.0 悬浮窗默认关闭解决方案

前言

在谷歌往Android中加入悬浮窗口功能时就表示希望开发者只用其来做用户通知,修改的悬浮窗功能潜在一定的安全隐患,不过手机厂商可不这么认为,于是本来被用于通知的悬浮窗被改成了其他的功能。我们都知道Android 6.0中,系统新增应用授权机制,还默认禁用了“浮动窗口”权限,所以悬浮窗功能只能当作通知使用。

  

直接上错误异常信息

android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@60838a -- permission denied for this window type
at android.view.ViewRootImpl.setView(ViewRootImpl.java:591)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:310)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)
at android.app.Dialog.show(Dialog.java:319)
....


一、遇到问题

Android 6.0 使用悬浮窗崩溃问题 (permission denied for this window type)

当你使用targetSdkVersion=22 ,而且添加了

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
权限,正常可以使用悬浮窗,然后修改targetSdkVersion=23,重新编译后依然能使用,也就是说只要一次授权了 就不在检测悬浮窗权限了。这是遇到的坑需要注意,卸载重装就好了

二、解决方案

使用TYPE_TOAST

getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);

优点: 不需要权限,都能显示

缺点: API level<19 的机器(MIUI除外),要有
android.permission.SYSTEM_ALERT_WINDOW
权限并且将 type 设置为
WindowManager.LayoutParams.TYPE_PHONE
或者
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
可以显示但没有交互

为什么TYPE_TOAST就不要权限呢?查看Android源码

public int checkAddPermission(WindowManager.LayoutParams attrs) {
int type = attrs.type;

if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
|| type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
return WindowManagerImpl.ADD_OKAY;
}
String permission = null;
switch (type) {
case TYPE_TOAST:
// XXX right now the app process has complete control over
// this...  should introduce a token to let the system
// monitor/control what they are doing.
break;
case TYPE_INPUT_METHOD:
case TYPE_WALLPAPER:
// The window manager will check these.
break;
case TYPE_PHONE:
case TYPE_PRIORITY_PHONE:
case TYPE_SYSTEM_ALERT:
case TYPE_SYSTEM_ERROR:
case TYPE_SYSTEM_OVERLAY:
permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
break;
default:
permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
}
if (permission != null) {
if (mContext.checkCallingOrSelfPermission(permission)
!= PackageManager.PERMISSION_GRANTED) {
return WindowManagerImpl.ADD_PERMISSION_DENIED;
}
}
return WindowManagerImpl.ADD_OKAY;
}


这个方法是往系统的WindowManager里addView的时候做权限检查用的,除了TYPE_TOAST外,其他的都需要添加权限 。

2. 先进行权限检测,引导用户开启

private static final int REQUEST_CODE = 1;
private  void requestAlertWindowPermission() {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE) {
if (Settings.canDrawOverlays(this)) {
Log.i(LOGTAG, "onActivityResult success");
}
}
}


手动设置方式

(Android 6.0+:设置——应用——右上角齿轮——「在其他应用的上层显示」)

3. 更改targetSDKVersion=22后,将被继续使用旧有规则,用户在安装的时候不得不接受所有权限,安装后app就有了那些权限,在Manifest里添加
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
权限 也能正常使用了。

如果想了解更详细可以参考

* http://www.liaohuqiu.net/cn/posts/android-windows-manager/

本人水平有限, 如有错误, 欢迎指正, 以免误导他人
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: