时隔16年Jeff Barr重返10.23-25 QCon上海站,带你看透AI如何重塑软件开发! 了解详情
写点什么

贝壳找房解决全局悬浮窗问题

  • 2019-09-24
  • 本文字数:2521 字

    阅读完需:约 8 分钟

贝壳找房解决全局悬浮窗问题

从百度打开贝壳找房 app 后要在应用每个界面显示个悬浮按钮, 说到悬浮按钮我们首先会想到 WindowManager。


我们在接到这个需求后也是按照惯用方法,使用 WindowManager 添加悬浮窗。



当前问题:必须打开贝壳找房的“悬浮窗”权限后才能显示

问题原因

Android6.0、Android7.1、Android8.0 版本对 WindowManager 的限制越来越多, 不同安卓版本可以使用 SYSTEM_ALERT、TYPE_PHONE、TYPE_TOAST、TYPE_SYSTEM_OVERLAY 类型,但前置条件是用户授权,而悬浮窗权限默认是关闭,在调试悬浮窗功能时可能出现各种坑。


例如:“android.view.WindowManager$BadTokenException: Unable to add window”、不显示悬浮窗等。

技术对标

从“今日头条”的广告展位打开“京东商城”后,打开每个京东商城的界面后都会显示“返回头条”。 这跟我们的需求是一致的,在系统设置里查看“京东商城”的悬浮窗权限是关闭的, 京东商城是如何做到的?



京东商城



京东商城布局


使用 uiautomakeviewer 抓布局后可以看出京东商城没使用 WindowManager(如果是 WindowManager 实现的悬浮窗,在 uiautomakeviewer 里无法选中), 而是在根节点添加个子 View, 悬浮窗是 setContentView()的兄弟 View。


划重点:从上面图片看出根节点是 FrameLayout, 它就是 Activity 的根节点 DecorView。 我们在 Activity 的 onCreate 函数里 setContentView, 其实就是向 PhoneWindow 类的 mDecor 添加子 View。

解决方案

通过对比京东商城 app, 找到了显示悬浮窗的方法。新的问题又来了, 如果在每个界面都添加这个悬浮按钮:


1、在 BaseActivity 里实现是否可行?


原理上没问题, 但贝壳找房使用了插件化,需要所有插件再编译一遍,代价有点大;


2、Activity 的生命周期是被谁触发的, 在 onCreate 或 onStart 里执行不就行了?


划重点:


(1)Activity 的生命周期函数是被 ActivityThread 类的 Instrumentation 类触发的, 而且 Android 在 Application 类里提供了回调接口。


(2)不管应用是否插件化,UI 界面都运行在同一个进程里,即公用一个进程上下文。


(3)必须先执行 setContentView,然后再添加悬浮窗,这样才能保证悬浮窗在上面(根节点 DecorView 是 FrameLayout)。


(4)在 onCreate 或 onStart 函数里执行添加悬浮窗逻辑有什么区别?区别在于 onStart 函数可以向已打开的 Activity 里添加悬浮窗。


核心代码:


在 onStart 函数里判断是否需要显示悬浮窗、悬浮窗是否已添加等条件后, 再添加悬浮窗。


 1 ((Application)mApplicationContext).registerActivityLifecycleCallbacks( 2        new Application.ActivityLifecycleCallbacks() { 3          @Override public void onActivityCreated(final Activity activity, Bundle savedInstanceState) { 4          } 5 6          @Override public void onActivityStarted(final Activity activity) { 7            if (TextUtils.isEmpty(sBackName) 8                || TextUtils.isEmpty(sBackUrl)) { 9              return;10            }1112            FrameLayout root = (FrameLayout) activity.getWindow().getDecorView();13            View linkView = root.findViewById(R.id.ll_deeplink_beike);14            if (linkView == null) {15              //如果已添加则能找到16              View view = UIUtils.inflate(R.layout.layout_baidu_deeplink_window,17                  null);18              TextView tvBackName = (TextView) view.findViewById(R.id.tv_back_name);19              LinearLayout ltBack = (LinearLayout) view.findViewById(R.id.lt_back);20              tvBackName.setText(UIUtils.getString(R.string.back_baidu, sBackName));21              ltBack.setOnClickListener(new View.OnClickListener() {22                @Override public void onClick(View view) {23                  Intent intent = new Intent();24                  intent.setData(Uri.parse(sBackUrl));25                  intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);26                  try {27                    activity.startActivity(intent);28                  } catch (ActivityNotFoundException ex) {29                    ex.printStackTrace();30                  }31                }32              });3334              FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,35                  ViewGroup.LayoutParams.WRAP_CONTENT);36              layoutParams.topMargin = (int)(activity.getResources().getDisplayMetrics().heightPixels * 0.75);37              layoutParams.leftMargin = 0;38              root.addView(view, layoutParams);39            } else {40              //do nothing41            }42          }4344          @Override public void onActivityResumed(Activity activity) {4546          }4748          @Override public void onActivityPaused(Activity activity) {4950          }5152          @Override public void onActivityStopped(Activity activity) {5354          }5556          @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {5758          }5960          @Override public void onActivityDestroyed(Activity activity) {6162          }63        });
复制代码

小结

如果再遇到悬浮窗的需求时,慎重使用 WindowManager,因为 Android 对 WindowManager 有各种权限限制;而在 DecorView 添加 View 的方式不受 Android 各个版本限制。


推荐使用添加 View 的方式替代 WindowManager。


感悟:从技术角度多对标别的产品,找出产品或技术上的亮点,想想自己实现这个功能该怎么做,然后再看看别人怎么做的,取长补短。


作者介绍:


作者大上(企业代号名),目前负责贝壳找房 App 安卓端研发工作。


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/3hXyFCgclsuoznNQ2ulC4g


2019-09-24 16:082037

评论

发布
暂无评论
发现更多内容

闺蜜机行业市场销量涨超42%,小度科技持续领跑行业

科技大数据

城市感知网络体系,构筑全域数字化新基石

脑极体

AI

鸿蒙适配unity的交互方法

cfx

鸿蒙 HarmonyOS HarmonyOS NEXT

鸿蒙应用开发中的生命周期管理:从组件到应用的全流程解析

谢道韫

鸿蒙 HarmonyOS HarmonyOS NEXT 实践分享

11.多用组合和少继承

杨充

什么是AI大模型?看deepseek用通俗易懂的语言解释

我再BUG界嘎嘎乱杀

人工智能 AI AI大模型 大模型 大语言模型

Arthas vmtool(从 jvm 里查询对象,执行 forceGc)

刘大猫

Java 监控 Arthas 监控工具 vmtool

湖仓一体架构在金融典型数据分析场景中的实践

镜舟科技

数据分析 金融 存算分离架构 StarRocks 湖仓一体

AI工具如何一键生成图表?5个流行的图表生成软件盘点!

职场工具箱

人工智能 图表 AI软件 AIGC 可视化工具

从0到上线,CodeBuddy 如何帮我快速构建旅游 App?

VyrnSynx

CodeBuddy首席试玩官

手动开发?给我一条提示词,CodeBuddy能做的你都做不到!

VyrnSynx

CodeBuddy首席试玩官

Kagi搜索:互联网搜索的净土,值得你的每一分钱

AI段舸

AI 搜索软件

YashanDB 知识库|STATISTICS_LEVEL 设置为 ALL,性能掉到冰点?一条参数搞清楚根因

数据库砖家

数据库

现代框架对SEO的深度影响

溪抱鱼

国际化 SEO SEO工具

关于懒加载,LazyForEach和Repeat的区别,哪一个性能更好呢?

cfx

鸿蒙 开发工具 HarmonyOS HarmonyOS NEXT

这款AI助手竟能自动生成行程+前端代码?

VyrnSynx

CodeBuddy首席试玩官

常见应用层DDoS攻击

天翼云开发者社区

安全 DDoS

从AI助手到个性化数字分身:WeClone & Second Me打造本地化、私有化的个性化AI代理系统

汀丶人工智能

人工智能

使用LLaMA-Factory快速训练自己的专用大模型

我再BUG界嘎嘎乱杀

人工智能 AI 大模型

AI实践探索:辅助生成测试用例

小巫debug日记

测试用例 AI编程

室内LED全彩显示屏P3与P5

Dylan

LED显示屏 全彩LED显示屏 led显示屏厂家 户内led显示屏 规格说明

需求分析不好做?这门华为新课免费试听!

YG科技

莫想到有一天得重新写个 etcd client

八苦-瞿昙

TikTok直播卡顿怎么解决?教你几个方法!

Ogcloud

SD-WAN tiktok直播 tiktok直播网络 tiktok网络 sd-wan专线

阿里Java开发手册:编程规约、异常日志、单元测试、安全规 约、MySQL 数据库、工程结构、设计规约!

程序员高级码农

Java 程序员 java 技术提升

用 CodyBuddy 帮我写自动化运维脚本

悟空聊架构

AI 悟空聊架构 CodeBuddy首席试玩官

100台电脑局域网搭建攻略和设备配置指南

Ogcloud

局域网 企业组网 局域网组建 局域网搭建 企业网络搭建

连锁药店如何安全访问总部运营系统?贝锐花生壳带来解决方案

贝锐

内网穿透 ERP

uniapp跨平台开发HarmonyOS NEXT应用初体验

幽蓝计划

鸿蒙跨平台开发

《算法导论(第4版)》阅读笔记:p14-p16

codists

算法

uniapp开发HarmonyOS NEXT应用之项目结构详细解读

幽蓝计划

贝壳找房解决全局悬浮窗问题_文化 & 方法_大上_InfoQ精选文章