悬浮窗上线
[ 参考点:
悬浮窗(权限启动申请) || 悬浮窗( 权限使用时申请 )]
-----------------------------------------------------------------------------------------------------
1.如何申请权限
首先静态申请一下
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />复制代码
然后为了兼容高API,需要进行动态权限申请,这里需要根据API版本以及厂商进行区分了。如果版本大于26使用TYPE_APPLICATION_OVERLAY的方式即可,否则使用TYPE_PHONE。其次一般6.0以前是不需要动态申请悬浮窗权限的,但小米是个特例,而且小米不同版本申请的方式可能还不一样,在6.0以上申请方式和其他手机一样,但是6.0以下就不同了
小米6.0以下申请权限
小米6.0以下申请权限和小米MIUI版本有关,如下图,需要对miui版本进行区分。具体的代码是我直接用的上面那个第三方库里的,有需要的可以去github上拉取直接用
正常的申请流程,也就是6.0以上手机的申请流程是跳到一个自己封装的空白权限申请界面,然后跳转到系统自带的悬浮窗申请界面进行权限申请,不管用户给不给权限,都关闭当前空页面。由于系统不同,所以在不同手机上看到的权限申请页面颜值可能就会不一样
2.如何实现悬浮窗可随手指拖动
思路非常简单,监听悬浮窗那个ImageView 的 onTouchListener 即可,在刚点击的ACTION_DOWN事件中记录当前的x,y位置,然后在每次移动后获取到本次移动的位置,二者相减就是需要移动的位置,这是自定义view的最基本操作了
3.如何实现悬浮窗左右边的吸顶效果
思路也非常简单,监听到手指抬起的动作后,判断当前位置是靠近左边还是右边,靠近左边就以位置动画的方式平移到左边,靠近右边就平移到右边
4.核心,添加悬浮窗的方法
中规中矩,按照android官方的方式添加即可。即获取系统的WindowManager,设置好参数,调用windowManager的addView()方法添加。需要注意的是,在隐藏悬浮窗的时候,最好是移除一下,下次需要显示的时候再添加
5. 坑点一 多次添加view会导致crash
这个是很多人都会碰到的,有时候没办法保证只添加一次,就算给了flag也会因为系统原因导致这个flag不准确。所以我在使用的时候就碰到了多次添加了的情况,最后的结果就是crash,解决方案就是在addView方法上加一个try...catch捕获住该异常
【addView不用try-catch,直接判断view是否有父布局就可以避免多次addView】
坑点二 oppo r9(5.1.1)上是有权限的,一直给返回没权限
这段代码是处理6.0以下权限申请的,上面红色部分是原来的代码,下面绿色部分是改过之后的。由于oppo在6.0以下每次检测悬浮窗权限都给false,导致项目中每次都弹框让用户去给权限,最后干脆就oppo 6.0以下直接默认都有权限好了。因为事实也如此,除了小米,其他品牌6.0以下都是有权限的
坑点三 如何处理输入法和悬浮窗的层级关系
微信里的悬浮窗是在输入法之下的,所以交互的同学也要求咱们的悬浮窗也要在输入法之下。我查看了一下WindowManager源码,我悬浮窗的优先级TYPE_APPLICATION_OVERLAY,上面大字写着明明是在输入法之下的,但是实际表现是在输入法之上了 ( windowManager是有一个flag专门用来设置悬浮窗和输入法的关系的,但是由于之前没设置,所以导致最后默认的输入法还是在悬浮窗之 )
既然源头找到了,设置起来就很简单了,如下图,设置好flag_alt_focusable_im这个flag即可。后面发现有一个帖子对flag总结得非常好,这里也推荐给大家,有想了解其他flag的同学可以去看一下这:blog.csdn.net/qq_33275597
坑点四 如何处理退出app或者按home键的时候关闭悬浮窗
这也是谷歌坑人的地方,都没地方设置这个悬浮窗是否只用到app内,所以默认在桌面上也会显示自己的悬浮窗。比如在微信里显示其他app的悬浮窗,这种糟糕的体验可想而知,用户不给你卸载就真是奇迹了。为了解决这个问题,最初的实现方式是对所有经过的activity进行记录,显示就加1,页面被挂起就减1,如果减到当前计数为0时说明所有页面已经关闭了,就可以隐藏悬浮窗了
但是实际上这么做还是有问题的,在部分手机上如果是在首页按返回键的话仍然不能隐藏,这个又是系统级的兼容性问题。为了解决这问题,我后面又做了一个处理,通过注册registerActivityLifecycleCallbacks监听app的前后台回调,检测到如果当前首页被销毁时,应该将悬浮窗进行隐藏
坑点五 多次点击悬浮窗以后,打开多个页面
如果你的悬浮窗点击事件是打开页面的话,这里需要注意了,别忘了将这个打开的页面的启动模式设置为singleTop或者是singleTask,从而复用同一个,远离一直按返回的地狱操作。
android:launchMode="singleTop"
android:launchMode="singleTask"
总结:悬浮窗的坑,只有真正做过的人才懂,不过还好现在已经有很多现成的第三方代码可以CV。但是就算是CV了也不代表可以高枕无忧,应用场景不同总还是会遇到其他的问题,我这里总结了自己遇到的部分坑点,以后还有的话会继续更新,我相信踩的坑越多,成长才会越快。我也希望自己的工作经历能够帮助到大家少走弯路,就像我借鉴了前辈们的成果一样。
最后,我做好了一个最简单的demo,有需求的小伙伴可以去github下载,github地址:
https://github.com/dongrong-fu/FloatDemo
作者:菜鸟说
链接:https://juejin.im/post/5dca1f2ee51d45746d3db35e