三星Alarm应用如何实现跨任意屏幕永久显示的类通知悬浮层
跨应用顶层常驻悬浮覆盖层实现方案
你一开始猜的自定义Toast思路走不通,系统对原生Toast的展示时长有硬限制,最长也就3.5秒,哪怕你用定时循环反复show Toast,在高版本安卓上也会被系统直接屏蔽,根本做不到稳定常驻。
三星闹钟的那种跨屏幕悬浮效果,本质就是用**悬浮窗权限(SYSTEM_ALERT_WINDOW)**实现的,这也是目前第三方应用能实现全场景顶层悬浮的唯一合规稳定方案,没有什么藏着的私有API,普通应用照着做就能出一样的效果,用来做新订单提醒完全适配。
具体实现步骤如下:
- 声明并申请悬浮窗权限
首先在项目的AndroidManifest.xml里加入权限声明:
这个权限属于特殊权限,不会随应用安装自动授予,需要主动引导用户到系统设置页手动开启。代码里可以通过<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />Settings.canDrawOverlays(context)判断当前是否已经拿到权限,没授权的话就唤起对应设置页让用户打开即可。 - 编写悬浮层UI布局
悬浮层的UI和普通页面的布局写法完全一致,你要展示的订单信息、操作按钮、点击/滑动交互都可以正常实现,灵活度比Toast、通知高很多。 - 通过WindowManager把悬浮层挂载到顶层
核心是调用系统的WindowManager服务,配置正确的窗口参数把自定义View添加到窗口最顶层,核心配置代码参考(Kotlin):// 获取系统窗口服务 val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager val layoutParams = WindowManager.LayoutParams().apply { // 版本适配:安卓8.0及以上必须用TYPE_APPLICATION_OVERLAY类型,低版本用TYPE_PHONE type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_PHONE } // 窗口标记:默认不抢占下层应用焦点,需要接收点击事件就加FLAG_NOT_TOUCH_MODAL flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN // 宽高根据自身布局设置即可,支持WRAP_CONTENT、MATCH_PARENT也可写固定数值 width = WindowManager.LayoutParams.WRAP_CONTENT height = WindowManager.LayoutParams.WRAP_CONTENT // 控制悬浮层位置,比如示例里的顶部居中就设置对应gravity和y轴偏移 gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL y = 120 format = PixelFormat.TRANSLUCENT } // 把提前inflate好的订单提醒View添加到窗口即可展示 windowManager.addView(orderAlertView, layoutParams) - 做好生命周期管理
订单处理完成后记得调用windowManager.removeView(orderAlertView)移除悬浮层,避免内存泄漏。如果需要悬浮层长时间驻留不被系统回收,可以把挂载逻辑放在前台Service里保活,注意安卓10以上启动前台Service必须配套展示对应的前台通知,不然会被系统直接杀死进程。
几个避坑提醒:
- 别信什么“永久Toast”“自定义Toast保活”的歪方案,安卓11之后系统会直接拦截后台应用频繁弹出的Toast,稳定性为0
- 不少国产ROM会默认禁用第三方应用的悬浮窗权限,申请权限的时候一定要给用户明确说明,告知开权限是为了及时推送订单提醒,降低用户拒绝概率
- 悬浮层的交互尽量做的简洁,核心放订单关键信息和接单/拒接按钮就行,别做太复杂的操作,避免干扰用户其他应用的正常使用
效果参考:
内容的提问来源于stack exchange,提问作者Ahmad Hamwi
相关产品推荐
相关产品推荐

