更新记录

1.0.2(2026-11-05)

更新说明

1.0.1(2026-11-05)

  • 支持按需启用 Android、鸿蒙和 iOS 的悬浮显示功能,插件接入后需主动开启。
  • iOS 使用画中画方案,需由接入项目配置所需的后台能力。
  • 关闭某个平台的功能后,停止该平台的悬浮显示和相关操作。

平台兼容性

uni-app x(5.33)

Chrome Safari Android Android插件版本 iOS iOS插件版本 鸿蒙 鸿蒙插件版本 微信小程序
× × 5.0 1.0.2 15 1.0.2 12 1.0.2 ×

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
√ √ √ √

图片悬浮窗插件

pow-floatwindow 适用于 uni-app x 项目,支持蒸汽模式 主要功能是

  1. app退到后台时展示系统级悬浮窗
  2. (安卓和鸿蒙)app退到后台时,使用api让app回到前台(比如来订单了自动让app到前台)

接入准备

  1. 将 pow-floatwindow 导入项目
  2. Android 和 iOS 都需要在导入本插件后,打自定义基座,并选择自定义调试基座运行项目。
  3. iOS 需完成本文的“iOS 配置”;鸿蒙需完成“鸿蒙配置”中的页面注册、生命周期接入和签名授权。
  4. 在应用启动时初始化插件,再调用业务接口。
平台 使用条件 接口使用差异
Android 5.0(API 21)及以上 获取系统悬浮窗授权 支持设置位置、拖动,以及请求返回前台。
鸿蒙 API 12 及以上 获取系统悬浮窗受限权限及签名授权 支持设置位置、拖动,以及请求返回前台;需接入悬浮窗承载页面。
iOS 15 及以上 设备支持画中画 使用画中画显示图片,位置和尺寸由系统管理;用户可通过系统画中画按钮返回应用。

初始化:initFloatWindow

在 App.uvue 中接入以下代码;已有生命周期回调时,将相应调用合并进去:

<script setup lang="uts">
// #ifdef APP-ANDROID || APP-IOS || APP-HARMONY
import { initFloatWindow } from '@/uni_modules/pow-floatwindow'
// #endif
// #ifdef APP-HARMONY
import { notifyAppShow, notifyAppHide } from '@/uni_modules/pow-floatwindow'
// #endif

onLaunch(() => {
  // #ifdef APP-ANDROID || APP-IOS || APP-HARMONY
  const enabled = initFloatWindow({
    iosEnable: true,
    androidEnable: true,
    harmonyEnable: true
  })
  console.log('当前平台插件是否已启用', enabled)
  // #endif
})

onAppShow(() => {
  // #ifdef APP-HARMONY
  notifyAppShow()
  // #endif
})

onAppHide(() => {
  // #ifdef APP-HARMONY
  notifyAppHide()
  // #endif
})
</script>

initFloatWindow(options: FloatWindowInitOptions): boolean

参数 类型 必填 说明
iosEnable boolean 是 是否启用 iOS 功能。还需在应用中配置 UIBackgroundModes 的 audio 项。
androidEnable boolean 是 是否启用 Android 功能。
harmonyEnable boolean 是 是否启用鸿蒙功能。

每个平台只读取对应开关,可按项目需要关闭其他平台。返回 true 表示当前平台插件已启用,授权状态和设备支持情况仍需分别查询。

未初始化或当前平台未启用时,操作接口不会执行,也不会调用回调;getCapabilities() 和 getFloatWindowState() 返回 null。 iOS 缺少后台音频配置时,即使传入 iosEnable: true,初始化也会返回 false。关闭已启用的平台会清理悬浮窗及事件监听,重新启用后需重新注册监听。

快速调用:检查授权并显示图片

以下代码放在业务页面的 <script setup lang="uts"> 中,在用户需要显示图片时调用 openImageWindow()。请先将图片放到自己项目的 /static/float-image.png。后续调用示例也在业务页面中使用;如同时编译 Web 等其他平台,请使用 APP-ANDROID || APP-IOS || APP-HARMONY 条件编译包裹插件导入及相关调用。

import {
  getCapabilities, getPermissionStatus, requestPermission, showFloatWindow
} from '@/uni_modules/pow-floatwindow'
import type { FloatWindowResult } from '@/uni_modules/pow-floatwindow/utssdk/interface'

function openImageWindow() {
  const capabilities = getCapabilities()
  if (capabilities == null || !capabilities.supported) {
    console.log('请先启用插件,并确认设备支持悬浮显示')
    return
  }

  getPermissionStatus((res: FloatWindowResult) => {
    if (res.errCode != 0) {
      console.log(res.msg)
      return
    }
    if (res.data?.getBoolean('granted') != true) {
      requestPermission((permissionRes: FloatWindowResult) => {
        console.log(permissionRes.msg)
      })
      return
    }

    showFloatWindow({
      source: '/static/float-image.png',
      width: 64,
      height: 64,
      x: 20,
      y: 240,
      draggable: true
    }, (showRes: FloatWindowResult) => {
      console.log(showRes.errCode, showRes.msg)
    })
  })
}

Android 首次调用可能会打开系统授权设置。用户返回应用后,再调用 openImageWindow(),或在页面 onShow 中重新检查权限。授权请求的回调不代表用户已经完成授权。

建议在应用前台调用显示接口,确认窗口出现后再切换到后台。iOS 必须在前台启动画中画,并等待显示成功的回调。

接口说明

下列带回调的接口均使用 FloatWindowCallback,即 (result: FloatWindowResult) => void。接口从 @/uni_modules/pow-floatwindow 导入,类型从 @/uni_modules/pow-floatwindow/utssdk/interface 导入。

查询平台能力:getCapabilities

getCapabilities(): FloatWindowCapabilities | null

返回字段 类型 说明
mode string 当前平台使用的悬浮显示方式。
supported boolean 当前实现或设备是否支持;不代表已经获得权限。
permissionRequired boolean 是否需要悬浮窗权限。
positionControl boolean 是否支持通过接口设置位置。
dragging boolean 是否支持用户拖动窗口。
bringToFront boolean 是否提供返回前台请求;不保证系统一定允许。
minVersion number,可选 最低系统版本或 API 级别。

调用位置调整、返回前台等接口前,可先检查对应字段。iOS 的 positionControl 和 bringToFront 均为 false。

查询和申请权限

  • getPermissionStatus(callback: FloatWindowCallback):查询当前权限状态,通过 res.data?.getBoolean('granted') 判断是否已授权。errCode == 0 仅表示查询成功。
  • requestPermission(callback: FloatWindowCallback):申请或检查当前平台的使用资格。
平台 requestPermission 的行为
Android 未授权时打开系统悬浮窗设置,返回 errCode: 1,并在 data.settingsOpened 中标记已打开设置;返回应用后应重新查询权限。已授权时返回 0。
鸿蒙 检查系统悬浮窗受限权限,不会弹出普通运行时授权窗口。未获授权时返回 -5,需按“鸿蒙配置”处理。
iOS 检查设备是否支持画中画,无单独的悬浮窗授权弹窗。支持时返回 0,不支持时返回 -5。

权限结果的 data.granted 表示是否已授权。Android、iOS 查询结果还提供 required;鸿蒙提供 supported 和 permission,申请结果还提供 requiresEligibleSignature。

iOS 的 getPermissionStatus 返回 granted: true、required: false;设备是否支持画中画应使用 getCapabilities().supported 或 requestPermission 判断。

显示悬浮窗:showFloatWindow

showFloatWindow(options: FloatWindowOptions, callback: FloatWindowCallback)

参数 类型 必填 默认值 / 说明
source string 是 图片地址,不能为空。可使用 /static/ 下的图片、本地图片文件路径或网络图片地址,网络图片建议使用 HTTPS。
width number 否 默认 64,建议传正数。
height number 否 默认 64,建议传正数。
x number 否 左上角横坐标,省略时靠屏幕右侧;传入时使用非负数。
y number 否 左上角纵坐标,省略时位于屏幕中部附近;传入时使用非负数。
draggable boolean 否 默认 true,是否允许拖动。

Android 的尺寸和坐标单位为 dp,鸿蒙为 px。iOS 只使用 source,其余参数不控制画中画窗口;窗口尺寸、位置和拖动交互由系统管理。

Android 的显示回调表示显示请求已提交,图片仍可能加载失败;需要结合窗口事件和状态查询处理后续结果。鸿蒙的显示回调依赖承载页面上报图片加载结果。iOS 在画中画实际启动后返回显示成功。

替换图片:setFloatWindowImage

setFloatWindowImage(source: string, callback: FloatWindowCallback)

import { setFloatWindowImage } from '@/uni_modules/pow-floatwindow'

setFloatWindowImage('/static/another-image.png', (res) => {
  console.log(res.errCode, res.msg)
})

source 的填写方式与显示接口相同。建议在悬浮窗已显示时调用;更新失败时根据回调处理,已显示的图片会尽量保留。此接口不负责打开悬浮窗,需要显示时仍应调用 showFloatWindow 并传入所需图片地址。

调整位置:setFloatWindowPosition

setFloatWindowPosition(position: FloatWindowPosition, callback: FloatWindowCallback)

import { getCapabilities, setFloatWindowPosition } from '@/uni_modules/pow-floatwindow'

const capabilities = getCapabilities()
if (capabilities != null && capabilities.positionControl) {
  setFloatWindowPosition({ x: 40, y: 200 }, (res) => {
    console.log(res.errCode, res.msg)
  })
}

x、y 均为必填的非负数,单位与显示接口一致。建议在窗口显示后调用,超出屏幕可用范围的位置会被限制在可用范围内。iOS 调用此接口返回 -5。

查询状态:getFloatWindowState

getFloatWindowState(): FloatWindowState | null

import { getFloatWindowState } from '@/uni_modules/pow-floatwindow'

const state = getFloatWindowState()
if (state != null) {
  console.log('是否显示', state.visible)
  console.log('当前图片', state.source)
}
返回字段 类型 说明
visible boolean 当前记录的悬浮显示状态。
permissionGranted boolean 当前记录的授权状态;需要重新确认时调用 getPermissionStatus。
source string 当前记录的图片地址,可能是转换后的本地路径。
x、y number 当前坐标,Android 为 dp、鸿蒙为 px。
width、height number 当前尺寸,Android 为 dp、鸿蒙为 px。

iOS 的坐标和尺寸字段固定返回 0,不能据此读取系统画中画窗口的实际位置和大小。状态可能随异步操作更新,宜在操作回调或窗口事件后查询。

隐藏和销毁悬浮窗

  • hideFloatWindow(callback: FloatWindowCallback):结束当前显示;需要再次显示时重新调用 showFloatWindow(options, callback)。
  • destroyFloatWindow(callback: FloatWindowCallback):结束当前显示并释放悬浮窗资源,用于业务结束时清理。
import { hideFloatWindow, destroyFloatWindow } from '@/uni_modules/pow-floatwindow'

function hideImageWindow() {
  hideFloatWindow((res) => console.log(res.errCode, res.msg))
}

function finishImageWindow() {
  destroyFloatWindow((res) => console.log(res.errCode, res.msg))
}

隐藏或销毁不等于关闭平台开关。如需停止使用插件,可再次调用 initFloatWindow,将当前平台开关设为 false。如果需要跨页面继续显示,请根据业务结束时机清理,不要在每次页面离开时自动销毁。

请求返回前台:requestBringToFront

requestBringToFront(options: FloatWindowBringToFrontOptions, callback: FloatWindowCallback)

import { getCapabilities, requestBringToFront } from '@/uni_modules/pow-floatwindow'

const capabilities = getCapabilities()
if (capabilities != null && capabilities.bringToFront) {
  requestBringToFront({ delayMs: 5000 }, (res) => {
    console.log(res.errCode, res.msg)
  })
}

delayMs 为可选的等待时间,单位毫秒,默认 0;传入 {} 表示立即请求。需要延时返回时,可以在应用前台安排请求,再切换到后台。

Android 和鸿蒙的返回前台请求受系统限制,应以回调结果判断,不能保证每次成功。鸿蒙需接入 notifyAppShow()、notifyAppHide() 才能正确跟踪应用前后台状态。iOS 调用此接口返回 -5,应由用户点击系统画中画中的返回应用按钮。

监听和取消监听事件

  • onFloatWindowEvent(callback: FloatWindowEventCallback):注册事件监听。
  • offFloatWindowEvent(callback: FloatWindowEventCallback):取消指定监听,必须传入注册时的同一个函数。
import { onFloatWindowEvent, offFloatWindowEvent } from '@/uni_modules/pow-floatwindow'
import type { FloatWindowEvent } from '@/uni_modules/pow-floatwindow/utssdk/interface'

const handleFloatWindowEvent = (event: FloatWindowEvent): void => {
  const type = event.getString('type')
  const message = event.getString('message')
  console.log('悬浮窗事件', type, message)
}

onLoad(() => {
  onFloatWindowEvent(handleFloatWindowEvent)
})

onUnload(() => {
  offFloatWindowEvent(handleFloatWindowEvent)
})

事件对象包含 type,部分事件还会提供 message。避免反复注册同一个监听;需要跨页面持续接收事件时,可在应用级统一管理。

事件 type 含义 可能触发的平台
show 窗口开始显示,不单独代表图片已经加载成功。 Android、鸿蒙、iOS
hide 调用隐藏接口后结束显示。 Android、鸿蒙、iOS
destroy 销毁悬浮窗。 鸿蒙、iOS
click 点击悬浮图片。 Android、鸿蒙
dragEnd 结束拖动。 Android、鸿蒙
systemClose 窗口被系统或用户关闭。 Android、iOS
restore 用户通过画中画返回应用。 iOS
error 图片加载或画中画启动等异常。 Android、iOS

各平台不会触发全部事件;判断某次调用的结果时,应同时处理该接口的回调。例如 Android 销毁时不发送 destroy 事件。

回调结果与错误处理

type FloatWindowResult = {
  errCode: number
  msg: string
  platform: string
  data?: UTSJSONObject
}

platform 为 android、harmony 或 ios。data 根据接口提供附加信息,读取前需判空。业务分支应使用 errCode 和 data,不要依赖 msg 的固定文案。

errCode 含义 / 处理方式
0 本次操作或查询成功,具体含义以接口说明为准。
1 Android 已打开授权设置,等待用户操作后重新检查权限。
-1 参数不正确,例如图片地址为空、位置为负数。
-2 Android 悬浮窗权限未授予或不可用。
-3 Android 当前没有可用的应用界面,请在应用界面可用时调用。
-4 操作失败、请求取消或等待超时,结合 msg 处理。
-5 当前平台、设备、权限条件不支持本次操作,或 iOS 画中画启动失败。
-6 图片加载或更新失败,请检查图片地址、文件和网络。

iOS 配置

  1. 导入插件
  2. 初始化时传入 iosEnable: true。
  3. 重新打包 iOS 自定义调试基座并安装,选择该基座运行。后台能力配置变更后,仅更新页面代码不能使配置生效。
  4. 使用支持画中画的 iOS 15 及以上设备,并确认系统画中画功能可用。
  5. 在应用前台调用 showFloatWindow,等待成功回调后再切换到后台。
<key>UIBackgroundModes</key>
<array>
  <string>audio</string>
</array>

该片段放在 Info.plist 的 <dict> 内。插件不会替宿主应用自动开启后台音频能力;应用需明确完成上述配置。正式发布前,请确认图片画中画的用途符合目标分发渠道的要求。

鸿蒙配置

注册悬浮窗承载页面

将仓库中的 pages/floatwindow/index.uvue 复制到自己项目的同名路径,并在 pages.json 的 pages 数组中添加以下配置。该页面是鸿蒙悬浮窗显示图片所需的承载页面,无需在业务中通过页面跳转打开:

{
  "path": "pages/floatwindow/index",
  "style": {
    "navigationStyle": "custom"
  }
}

请保留 pages/floatwindow/index 路径,以及页面中的图片加载和交互回调。同时按初始化示例,在 App.uvue 的应用前后台生命周期中调用 notifyAppShow 和 notifyAppHide。

接口 接入位置 / 用途
notifyAppShow() 鸿蒙专用,在应用进入前台时调用,用于确认返回前台请求的结果。
notifyAppHide() 鸿蒙专用,在应用进入后台时调用,用于更新前后台状态。
dispatchFloatWindowEvent(type: string) 承载页面转发点击、拖动结束等事件;普通业务页面通常只需注册事件监听。
dispatchFloatWindowImageLoad(revision: number, success: boolean) 承载页面上报图片加载结果;保留所提供页面的调用即可,业务页面不要手动上报。

处理“运行所需的权限没有签名授权”

本插件需要 ohos.permission.SYSTEM_FLOAT_WINDOW。应用声明此权限,但签名 Profile 没有包含相应授权时,设备会拒绝安装。处理步骤如下:

  1. 在华为 AppGallery Connect(AGC)中,为自己的应用申请系统悬浮窗受限权限,并按要求说明使用场景。能否获得授权,以华为审核结果为准。
  2. 获批后,重新生成并下载包含该权限授权的调试 Profile(.p7b),确认与项目包名、签名证书及当前调试设备匹配。
  3. 在 HBuilderX 项目的鸿蒙签名配置中替换 Profile;如果更换了签名证书或密钥,一并更新对应配置。
  4. 重新打包并运行到鸿蒙设备。安装成功后,初始化插件,调用 getPermissionStatus 检查授权,再调用 showFloatWindow。

正式发布也需要使用包含相应授权的发布签名资料。普通运行时授权弹窗、手机设置开关或重新生成普通调试签名不能替代此授权;删除系统悬浮窗权限声明会导致悬浮窗功能无法使用。

参考:安装报错处理说明、鸿蒙权限配置指南。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

Android 需要用户授予悬浮窗权限;鸿蒙系统浮窗需要 SYSTEM_FLOAT_WINDOW 系统授权;iOS 通过画中画显示图片帧。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

无

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。