悬浮窗,在大多数应用中还是很少见的,目前我们接触到的悬浮窗,差不多都是一些系统级的应用软件,例如:360安全卫士,腾讯手机管家等;在某些服务行业如金融,餐饮等,也会在应用中添加悬浮窗,例如:美团的偷红包,博闻金融快捷联系等。但两种悬浮窗还是有区别的:
- 系统悬浮窗:所有界面都会展示,包括主屏、锁屏
- 应用悬浮窗:只在应用Activity中展示。
一、窗口Window
在了解悬浮窗之前,首先我们需要认识一下Android窗口Window。Android Framework将窗口分为三个类型:
- 应用窗口:所谓应用窗口指的就是该窗口对应一个Activity,因此,要创建应用窗口就必须在Activity中完成了。
- 子窗口:所谓子窗口指的是必须依附在某个父窗口之上,比如PopWindow,Dialog。
- 系统窗口:所谓系统窗口指的是由系统进程创建,不依赖于任何应用或者不依附在任何父窗口之上,如:Toast,来电窗口等。
Framework定义了三种窗口类型,这三种类型定义在WindowManager的内部类LayoutParams中,WindowManager将这三种类型 进行了细化,把每一种类型都用一个int常量来表示,这些常量代表窗口所在的层,WindowManagerService在进行窗口叠加的时候,会按照常量的大小分配不同的层,常量值越大,代表位置越靠上面,所以我们可以猜想一下,应用程序Window的层值常量要小于子Window的层值常量,子Window的层值常量要小于系统Window的层值常量。Window的层级关系如下所示。
- 应用窗口:层级范围是1~99
- 子窗口:层级范围是1000~1999
- 系统窗口:层级范围是2000~2999
1.各级别type值在WindowManager中的定义分别为:
i.应用窗口(1~99)
|
|
ii.子窗口(1000~1999)
|
|
iii.系统窗口(2000~2999)
|
|
2.窗口flags显示属性在WindowManager中也有定义:
|
|
3.添加View到Window的流程代码:
|
|
悬浮窗添加原理:View添加到Window源码解析
Window在Android系统中十分重要,其Activity,Dialog的创建都离不开Window.具体Activity,Dialog是怎么添加到Window上的,详情如:
Activity的加载流程;
Dialog加载绘制流程
二、两种悬浮窗
在前言中已说到,悬浮窗在app中,分为两种:系统级别和应用级别。其中系统级别可以在任何界面展示,包括主屏、锁屏(看需要),应用级别只在应用中展示。通过上面对Window的认识,我们可以知道实现方式:
- 系统级别可以通过type设置为:TYPE_TOAST、TYPE_PHONE、TYPE_SYSTEM_ALERT;
- 应用级别可以通过type设置为:TYPE_APPLICATION、TYPE_APPLICATION_ATTACHED_DIALOG;
悬浮窗添加流程:
WindowManager.addView -> ViewRootImpl.setView -> WindowSession.addToDisplay(AIDL进行IPC) -> WindowManagerService.addWindow() -> ViewRootImpl.setView
1.系统悬浮窗
对于系统级别的悬浮窗来说,不同的设置,不同的Android版本,需要权限和交互都不同。通过阅读源码android4.4知:
android 7.1.1的addWindow方法为:
|
|
权限检查checkAddPermission()方法:
|
|
window的flags属性添加adjustWindowParamsLw()方法
|
|
由上可知:
- Type为TYPE_TOAST:版本低于android4.4的,不能接受触摸事件,无法操作;版本高于Android 7.1.1的无法添加悬浮窗
- Type为TYPE_PHONE:所有android版本都需要权限,版本低于android6.0的manifest中添加权限android.Manifest.permission.SYSTEM_ALERT_WINDOW即可,高于andorid6.0的需要判断权限且手动添加。
- Type为TYPE_SYSTEM_ALERT:同TYPE_PHONE
所以系统级别的悬浮窗,android不同版本需要特别处理。
2.应用悬浮窗
对于应用悬浮窗来说,android版本对其影响不大。
- Type为TYPE_APPLICATION:只要Activity建立了,就可以添加。
- Type为TYPE_APPLICATION_ATTACHED_DIALOG:需要在Activity获取焦点,并且用户可操作时才可添加。
三、悬浮窗的实现
悬浮窗添加比较简单,主要是由WindowManager接口的实现类WindowManagerImpl进行操作,WindowManager接口又继承至ViewManager,其中主要方法为:
|
|
主要实现代码:
|
|
悬浮窗源码:https://github.com/awenzeng/FloatWindowDemo
四、注意
1.应用悬浮窗WindowManager的获取环境必须是Activity环境,系统悬浮窗可以Activity环境,也可以是全局的环境。如:
|
|
2.应用级别悬浮窗也可以通过系统级别的方式实现,主要控制一下显示与隐藏就好。但如果只在应用中展示悬浮窗,建议使用应用级别,那样会省去许多不必要的麻烦。
3.系统级别Type为TYPE_PHONE、TYPE_SYSTEM_ALERT是权限判断及设置代码:
|
|