AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

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

  • 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:081730

评论

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

扫码联网系统(源码+文档+部署+讲解)

深圳亥时科技

2025多端社交圈子论坛兴趣社区圈子论坛小程序 圈子社区论坛系统源码

DUOKE七七

php MySQL uniapp

培训中心教务系统(源码+文档+部署+讲解)

深圳亥时科技

火语言RPA--图鉴打码

火语言RPA

数字先锋 | 车企,出海!天翼云AOne擦亮车企“智慧服务”新名片!

天翼云开发者社区

云计算 公有云 边缘安全 安全防护

Omnissa Horizon Windows OS Optimization Tool 2412 - Windows 系统映像优化工具

sysin

Firefox 135, Chrome 135, Chromium 135 官网离线下载 (macOS, Linux, Windows)

sysin

firefox

VMware Tanzu Kubernetes Grid Integrated Edition (TKGI) 1.21 - 运营商 Kubernetes 解决方案

sysin

Kubernetes Tanzu

ixBrowser指纹浏览器配置教程

kookeey代理严选

代理IP 跨境电商 亚马逊运营 Tiktok shop 指纹浏览器

利用ima.copilot,打造你的AI知识库

老张

人工智能 知识库 DeepSeek ima.copilot

我们究竟畏惧AI什么?

这不科技

AI

2025大厂年终奖揭秘:有人拿50个月工资,有人直接撒钱?

王中阳Go

程序员

Magnet for Mac:智能窗口管理,提升工作效率的神器!

Rose

VMware Fusion Pro 13 for Mac(VM虚拟机) v13.5.0中文激活版

Rose

唤醒 AI 算力,专有云 ABC Stack 面向企业级智算平台的 GPU 提效实践

百度Geek说

"扒光"淘宝商品详情价格主图详情图数据的秘密武器!不用爬虫,API让你躺着赚信息差

代码忍者

淘宝API接口

AI口语练习APP的技术难点

北京木奇移动技术有限公司

软件外包公司 AI口语练习 AI英语练习

AI招聘助手的主要功能

北京木奇移动技术有限公司

AI技术 AI招聘 软件外包公司

Aiseesoft AnyCoord for Mac(GPS虚拟定位软件) v1.0.36激活版

Rose

a16z 最新语音 AI 报告:语音将成为关键切入点,但非最终产品本身(含最新图谱)

声网

低代码开发是传统开发的替代,还是补充?

秃头小帅oi

面向 Workload 级别的灵活可配置 Serverless 弹性解决方案

阿里巴巴云原生

阿里云 Serverless 云原生

数字先锋 | 竞技科研蓝海,中南大学先“算”一步!

天翼云开发者社区

云计算 智算平台 算力建设

企业在财务规划过程中,如何避免零基预算的常见陷阱

智达方通

全面预算管理 财务规划和分析 财务规划

1688APP 原数据 API 接口的开发、应用与收益

科普小能手

数据挖掘 阿里巴巴 1688 电信运营商 API 接口

华茂集团力挺富卫集团上市,补偿公告彰显信心,共绘股权辉煌未来

科技汇

人工智能与低代码,如何让数据分析从“苦力活”变成“轻松事”?

天津汇柏科技有限公司

人工智能 低代码,

“全球金牌敏捷课程” · 2 月 22-23 日 CSM 认证课程 · Jim 老师

ShineScrum

Scrum 敏捷 Scrum Master 敏捷教练认证 敏捷认证

Nexpose 7.5.0 for Linux & Windows - 漏洞扫描

sysin

Nexpose

Gitea Enterprise 23.0.0 (Linux, macOS, Windows) - 本地部署的企业级 Git 服务

sysin

git Gitea

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