Android悬浮窗的实现

本文详细介绍了如何在Android中实现悬浮窗,包括悬浮窗的插入接口、权限设置、LayoutParams配置,以及如何在不同Android版本上适配。此外,还展示了如何添加拖动功能、图片自动播放和视频小窗口等实用特性,提供了完整的源码供参考。
摘要由CSDN通过智能技术生成

Android悬浮窗的实现


*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

本文也发布于本人的知乎文章:https://zhuanlan.zhihu.com/p/394211126

0. 前言

现在很多应用都使用到悬浮窗,例如微信在视频的时候,点击Home键,视频小窗口仍然会在屏幕上显示。这个功能在很多情况下都非常有用。那么今天我们就来实现一下Android悬浮窗,以及探索一下实现悬浮窗时的易错点。


1. 实现原理

1.1 悬浮窗插入接口

在实现悬浮窗之前,我们需要知道通过什么接口,能够将一个控件放入到屏幕中去。
  Android的界面绘制,都是通过WindowMananger的服务来实现的。那么,既然要实现一个能够在自身应用以外的界面上的悬浮窗,我们就要利用WindowManager来“做手脚”。

(frameworks/base/core/java/android/view/WindowMananger.java)

@SystemService(Context.WINDOW_SERVICE)
public interface WindowManager extends ViewManager {
   
	...
}

WindowManager实现了ViewManager接口,可以通过获取WINDOW_SERVICE系统服务得到。而ViewManager接口有addView方法,我们就是通过这个方法将悬浮窗控件加入到屏幕中去。

1.2 权限设置及请求

悬浮窗需要在别的应用之上显示控件,很显然,这需要某些权限才可以。
  在API Level >= 23的时候,需要在AndroidManefest.xml文件中声明权限SYSTEM_ALERT_WINDOW才能在其他应用上绘制控件。

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

除了这个权限外,我们还需要在系统设置里面对本应用进行设置悬浮窗权限。该权限在应用中需要启动Settings.ACTION_MANAGE_OVERLAY_PERMISSION来让用户手动设置权限。

startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), REQUEST_CODE);
1.3 LayoutParam设置

WindowManageraddView方法有两个参数,一个是需要加入的控件对象,另一个参数是WindowManager.LayoutParam对象。
  这里需要着重说明的是LayoutParam里的type变量。这个变量是用来指定窗口类型的。在设置这个变量时,需要注意一个坑,那就是需要对不同版本的Android系统进行适配。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
   
	layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
   
    layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}

在Android 8.0之前,悬浮窗口设置可以为TYPE_PHONE,这种类型是用于提供用户交互操作的非应用窗口。
  而Android 8.0对系统和API行为做了修改,包括使用SYSTEM_ALERT_WINDOW权限的应用无法再使用一下窗口类型来在其他应用和窗口上方显示提醒窗口:

  • TYPE_PHONE
  • TYPE_PRIORITY_PHONE
  • TYPE_SYSTEM_ALERT
  • TYPE_SYSTEM_OVERLAY
  • TYPE_SYSTEM_ERROR
      如果需要实现在其他应用和窗口上方显示提醒窗口,那么必须该为TYPE_APPLICATION_OVERLAY的新类型。
      如果在Android 8.0以上版本仍然使用TYPE_PHONE类型的悬浮窗口,则会出现如下异常信息:
android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@f8ec928 -- permission denied for window type 2002

2. 具体实现

下面来讲解一下悬浮窗的具体实现方式。
  完整的源码地址:https://github.com/dongzhong/TestForFloatingWindow

为了让悬浮窗与Activity脱离,使其在应用处于后台时悬浮窗仍然可以正常运行,这里使用Service来启动悬浮窗并做为其背后逻辑支撑。
  在启动服务之前,需要先判断一下当前是否允许开启悬浮窗。

(MainActivity.java)

public void startFloatingService(View view) {
   
	...
    if (!Settings.canDrawOverlays(this)) {
   
		Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
        startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0);
    } else {
   
        startService(new Intent
  • 116
    点赞
  • 411
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 47
    评论
评论 47
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董小虫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值