更新记录

1.0.0(2026-05-17) 下载此版本

初次提交


平台兼容性

uni-app

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
× × × × × 5.0 × ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × × × ×

uni-app x(5.08)

Chrome Safari Android Android插件版本 iOS iOS插件版本 鸿蒙 微信小程序
- - 5.0 1.0.0 12 1.0.0 -

其他

多语言 暗黑模式 宽屏模式

laoqianjunzi-float

原生悬浮球卡片插件。

这是一个基于 UTS 实现的 uni-app x / uni-app 原生浮层插件,提供两套能力:

  • 高阶统一 API:getFloatingWindowManager()
  • 原始 Native API:getNativeFloatManager()

插件面向以下场景:

  • Android 系统悬浮窗网页浮层
  • Android 系统级视频画中画(PiP)
  • iOS 应用内网页浮层
  • iOS 系统视频画中画(PiP)
  • Harmony 应用内网页浮层
  • Web 页面内模拟悬浮浮层

如果你要做的是“悬浮球 / 悬浮卡片 / 网页浮层 / 视频小窗 / 回到应用前台”这一类能力,这个插件可以直接接入。

功能概览

  • 支持 webviewvideo-url 两类内容模型
  • 支持打开、关闭、刷新、移动、执行 JS、播放/暂停/跳转视频
  • 支持窗口状态查询、支持性检查、参数校验
  • 支持窗口事件监听与错误监听
  • 支持旧版原始能力接口,可直接创建 ball / card / webview
  • 支持 Android / iOS / Harmony / Web 多端差异化落地

平台支持矩阵

高阶统一 API

模式 平台 内容类型 说明
android-overlay-window Android webview 系统悬浮层,需要悬浮窗权限
android-system-video-pip Android 8.0+ video-url 系统级视频 PiP,需要宿主 Activity 合并
ios-in-app-float iOS 12+ webview 应用内浮层,必须传 ownerPageId
ios-out-app-pip iOS 12+ video-url 系统视频 PiP,依赖 iOS 后台音频模式
harmony-overlay-window Harmony webview 应用内浮层,需要页面中挂载宿主组件
web-overlay-window Web webview 页面内 DOM/iframe 模拟浮层,不是系统悬浮窗

原始 Native API

getNativeFloatManager() 直接暴露底层窗口能力,支持以下模式:

模式 说明
ball 悬浮球
card 悬浮卡片
webview 网页浮层

更推荐新项目优先使用 getFloatingWindowManager(),因为它已经统一了平台差异、状态管理、事件派发与错误处理。

版本与环境要求

  • HBuilderX:5.0+,建议直接使用当前较新版本
  • uni-app / uni-app x4.0+
  • Android:minSdkVersion 21+
  • iOS:12+
  • Harmony:插件内声明为 5.1+

安装方式

将插件导入项目的 uni_modules 目录后,直接从插件根入口导入即可:

import {
  getFloatingWindowManager,
  getNativeFloatManager,
  type FloatingWindowOpenOptions,
  type FloatingWindowEvent,
  type FloatingWindowFail,
} from '@/uni_modules/laoqianjunzi-float'

不要直接导入 utssdk/app-android/*utssdk/app-ios/* 这一类平台实现文件,统一从:

  • @/uni_modules/laoqianjunzi-float

进入。

接入前必读

1. 原生配置的生效方式

插件已经自带了平台侧原生配置:

  • Android:SYSTEM_ALERT_WINDOW 权限、PiP 宿主 Activity
  • iOS:UIBackgroundModes = audio

但这些配置不是“导入后立刻在标准基座里可见”。涉及原生能力时,建议这样验证:

  • 真机调试:使用自定义基座 / 自定义运行基座
  • 发包验证:使用云打包或正式本地构建

否则你可能会遇到这类现象:

  • Android PiP 支持检查提示缺少宿主 Activity
  • Android 悬浮权限判断正常,但浮层不真正弹出
  • iOS PiP 行为和最终发包结果不一致

2. 平台差异不是 Bug

这个插件不是“所有平台一套完全相同行为”的简单封装,而是把多端能力统一到了同一套 API 之下。

例如:

  • Android overlay 是系统层悬浮窗
  • iOS in-app-float 是应用内浮层,不是系统悬浮窗
  • Harmony / Web 是应用页面内浮层
  • 视频 PiP 只在 Android / iOS 提供

所以建议在正式 open() 前,先执行:

  • checkSupportSync()
  • validateOpenOptionsSync()

快速开始

高阶 API:打开一个网页浮层

import {
  getFloatingWindowManager,
  type FloatingWindowOpenOptions,
} from '@/uni_modules/laoqianjunzi-float'

const manager = getFloatingWindowManager()

function resolveOverlayMode() {
  // #ifdef APP-ANDROID
  return 'android-overlay-window'
  // #endif
  // #ifdef APP-IOS
  return 'ios-in-app-float'
  // #endif
  // #ifdef APP-HARMONY
  return 'harmony-overlay-window'
  // #endif
  // #ifdef WEB
  return 'web-overlay-window'
  // #endif
  return 'web-overlay-window'
}

const openOptions = {
  requestId: 'demo-open-1',
  tag: 'demo-overlay',
  mode: resolveOverlayMode(),
  contentType: 'webview',
  ownerPageId: 'demo-page-001',
  frame: {
    x: 24,
    y: 160,
    width: 320,
    height: 220,
  },
  appearance: {
    title: '网页浮层',
    backgroundColor: '#FFFFFF',
    cornerRadius: 16,
    showTitleBar: true,
    showCloseButton: true,
  },
  'https://www.baidu.com/',
    jsBridgeEnabled: true,
  },
} as FloatingWindowOpenOptions

const support = manager.checkSupportSync(openOptions.mode, openOptions.contentType)
if (!support.supported) {
  console.log('当前平台暂不支持:', JSON.stringify(support))
} else {
  const validation = manager.validateOpenOptionsSync(openOptions)
  if (validation.valid) {
    manager.open(openOptions)
  } else {
    console.log('参数校验失败:', JSON.stringify(validation))
  }
}

事件监听与错误监听

import {
  getFloatingWindowManager,
  type FloatingWindowEvent,
  type FloatingWindowFail,
} from '@/uni_modules/laoqianjunzi-float'

const manager = getFloatingWindowManager()

let eventListenerId : number | null = null
let errorListenerId : number | null = null

function bindFloatEvents() {
  eventListenerId = manager.onWindowEvent((event : FloatingWindowEvent) => {
    console.log('窗口事件', JSON.stringify(event))
  })

  errorListenerId = manager.onError((err : FloatingWindowFail) => {
    console.log('窗口错误', err.errCode, err.errMsg)
  })
}

function unbindFloatEvents() {
  manager.offWindowEvent(eventListenerId)
  manager.offError(errorListenerId)
  eventListenerId = null
  errorListenerId = null
}

页面销毁时清理 page-owned 窗口

ios-in-app-float 属于 page-owned 范围,建议页面销毁时做清理:

import {
  getFloatingWindowManager,
  type FloatingWindowPageCleanupOptions,
} from '@/uni_modules/laoqianjunzi-float'

const manager = getFloatingWindowManager()
const ownerPageId = 'demo-page-001'

onUnload(() => {
  const cleanupOptions = {
    ownerPageId: ownerPageId,
    reason: 'page-unload',
  } as FloatingWindowPageCleanupOptions
  manager.cleanupPageOwnedWindows(cleanupOptions)
})

Harmony 页面必须挂载宿主组件

Harmony 端的应用内浮层依赖宿主组件渲染。页面中必须包含:

<template>
  <!-- #ifdef APP-HARMONY -->
  <laoqianjunzi-float-host></laoqianjunzi-float-host>
  <!-- #endif -->

  <view class="page-root">
    <!-- 你的页面内容 -->
  </view>
</template>

如果 Harmony 页面没有挂这个组件,窗口可能创建成功,但实际没有可见宿主去承接渲染。

Android 悬浮权限处理

import { getFloatingWindowManager } from '@/uni_modules/laoqianjunzi-float'

const manager = getFloatingWindowManager()

// #ifdef APP-ANDROID
if (!manager.canDrawOverlaysSync()) {
  manager.openOverlayPermissionSettings()
}
// #endif

高阶 API 说明

getFloatingWindowManager()

返回统一窗口管理器,推荐优先使用。

核心方法

方法 说明
checkSupportSync(mode, contentType?) 检查当前平台是否支持指定模式
validateOpenOptionsSync(options) 在真正打开前做参数校验
getWindowStateSync(tag) 获取某个窗口当前状态
getActiveWindowTagsSync() 获取当前活跃窗口 tag 列表
open(options) 打开窗口
close(options) 关闭窗口
refresh(options) 更新内容、样式或行为
updateFrame(options) 更新位置与尺寸
callJS(options) webview 窗口执行 JS
playVideo(options) 播放 PiP 视频
pauseVideo(options) 暂停 PiP 视频
seekVideo(options) 跳转 PiP 视频进度
cleanupPageOwnedWindows(options) 清理页面归属窗口
canDrawOverlaysSync() Android 悬浮权限检查
openOverlayPermissionSettings() 打开 Android 悬浮权限页
bringAppToFront() 请求应用回到前台
onWindowEvent(callback) 监听窗口事件
offWindowEvent(listenerId?) 取消窗口事件监听
onError(callback) 监听错误事件
offError(listenerId?) 取消错误监听

FloatingWindowOpenOptions

打开窗口时最关键的参数如下:

字段 类型 必填 说明
tag string 窗口唯一标识
mode FloatingWindowMode 窗口模式
contentType 'webview' \| 'video-url' 内容类型
requestId string 业务请求标识,便于串联事件
ownerPageId string 条件必填 ios-in-app-float 必填;建议其它页面型模式也传
frame FloatingWindowFrame 窗口位置与尺寸
appearance FloatingWindowAppearance 标题栏、圆角、背景色等
behavior FloatingWindowBehavior 是否可拖动、是否替换已存在实例等
webview FloatingWindowWebViewContent 条件必填 contentType = webview 时需要
video FloatingWindowVideoContent 条件必填 contentType = video-url 时需要
extra UTSJSONObject 透传到原生侧的附加业务数据

FloatingWindowFrame

字段 说明
x 左上角横坐标
y 左上角纵坐标
width 宽度
height 高度

FloatingWindowAppearance

字段 说明
cornerRadius 圆角
showTitleBar 是否显示标题栏
showCloseButton 是否显示关闭按钮
backgroundColor 背景色
title 标题文本

FloatingWindowBehavior

字段 说明
canDrag 是否允许拖动
autoRestoreToApp 请求恢复到应用前台时的偏好
replaceExisting 打开同 tag 窗口时是否替换旧实例

FloatingWindowWebViewContent

满足以下三者之一即可:

  • url
  • html
  • assetPath

常用字段如下:

字段 说明
url 远程页面地址
html 直接注入 HTML 字符串
baseUrl html 模式下的基准地址
assetPath 本地资源路径
userAgent 自定义 UA
jsBridgeEnabled 是否启用 JS Bridge

FloatingWindowVideoContent

字段 说明
url 视频地址,必填
title 视频标题
subtitle 副标题
aspectRatio 比例字符串,如 16:9
autoEnter 是否自动进入 PiP
isMuted 是否静音
allowsExternalPlayback 是否允许外部播放
startPositionMs 初始播放进度

原始 Native API 说明

getNativeFloatManager()

原始接口更贴近底层平台实现,适合以下情况:

  • 已有旧版接入代码,暂时不想迁移
  • 只想控制一个简单悬浮球 / 卡片 / 网页层
  • 需要直接操作原始 ball / card / webview 结构

核心方法

方法 说明
canDrawOverlays() Android 悬浮权限检查
openOverlayPermissionSettings() Android 权限设置页
create(options) 创建窗口
show(id) 显示窗口
hide(id) 隐藏窗口
destroy(id) 销毁窗口
setRect(id, rect, animate) 更新位置与尺寸
setDragMode(id, mode) 更新拖动模式
setZIndex(id, zIndex) 更新层级
setFocusable(id, enabled) 是否可聚焦
setTouchThrough(id, enabled) 是否点击穿透
setAppScope(id, scope) 更新窗口归属范围
updateBall(id, options) 更新悬浮球样式
updateCard(id, options) 更新卡片样式
loadUrl(id, url) 加载 URL
loadHtml(id, html, baseUrl?) 加载 HTML
reload(id) 重新加载
goBack(id) webview 后退
goForward(id) webview 前进
clearCache(id) 清空缓存
setUserAgent(id, userAgent) 设置 UA
getUserAgent(id) 获取 UA
evalJs(id, script) 执行 JS
emit(id, type, payloadJson) 发消息到目标窗口
broadcast(type, payloadJson) 广播消息
call(id, options) 发起调用请求
respondRequest(id, requestId, ok, payloadJson) 响应请求
onMessage(callback) 监听原始消息
offMessage() 取消消息监听

原始接口示例

import {
  getNativeFloatManager,
  type NativeFloatCreateOptions,
} from '@/uni_modules/laoqianjunzi-float'

const nativeManager = getNativeFloatManager()

const options = {
  id: 'legacy-web-float',
  mode: 'webview',
  x: 20,
  y: 180,
  width: 300,
  height: 220,
  dragMode: 2,
  focusable: true,
  touchThrough: false,
  backgroundColor: '#00000000',
  dataJson: '{}',
  webview: {
    url: 'https://www.baidu.com/',
    bridgeName: 'NativeFloatBridge',
  },
} as NativeFloatCreateOptions

const created = nativeManager.create(options)
if (created) {
  nativeManager.show('legacy-web-float')
}

事件说明

高阶事件 FloatingWindowEvent

事件对象主要字段:

字段 说明
requestId 对应触发该事件的请求 ID
action 当前动作,如 open / close / refresh
tag 窗口唯一标识
mode 窗口模式
state 窗口状态
event 事件名
data 附带数据

常见事件名包括:

  • opened
  • closed
  • refreshed
  • frame-updated
  • js-called
  • webview-ready
  • webview-error
  • frame-dragged
  • native-close-request
  • restore-requested
  • video-ready
  • video-played
  • video-paused
  • video-seeked
  • pip-entered
  • pip-refreshed
  • restored-to-app
  • video-error

不同平台的事件触发时机会略有差异,但字段结构保持统一。

错误对象 FloatingWindowFail

字段 说明
errSubject 固定为 laoqianjunzi-float
errCode 错误码
errMsg 错误说明
action 触发错误的动作
tag 对应窗口 tag
mode 对应模式
requestId 对应请求 ID

常见错误码

错误码 说明
9012001 当前平台 / 模式不支持
9012002 缺少权限、后台模式或 Manifest 关键声明
9012003 内容类型不匹配,或当前动作不支持该内容
9012004 上下文未就绪,例如 App Context 尚未可用
9012006 原生执行失败或未知错误
9012007 系统版本过低
9012008 当前平台暂未实现该能力
9012009 同 tag 窗口已存在且不允许替换
9012010 目标窗口不存在
9012011 ownerPage / ownerPageId 不匹配

平台接入说明

Android

悬浮窗权限

android-overlay-window 需要 SYSTEM_ALERT_WINDOW。插件已自带权限声明,但你仍然要在业务侧处理授权流程:

  1. canDrawOverlaysSync() 判断
  2. 未授权时调 openOverlayPermissionSettings()
  3. 用户返回后重新判断,再调用 open()

Android PiP

android-system-video-pip 还有几个前置条件:

  • Android 版本必须 >= 26
  • 宿主包里必须存在 PiP Host Activity
  • 需要重新构建自定义基座或正式安装包,确保原生声明被合并

如果 checkSupportSync() 返回 missing-manifest-entry,优先检查的不是代码,而是:

  • 是否还在用旧基座
  • 是否重新打包让插件中的 AndroidManifest 合并进去

iOS

ios-in-app-float

这是应用内浮层,不是系统悬浮窗。重点限制:

  • 仅支持 webview
  • 必须传 ownerPageId
  • 建议页面卸载时调用 cleanupPageOwnedWindows()

ios-out-app-pip

这是系统视频 PiP。重点限制:

  • 仅支持 video-url
  • bringAppToFront() 当前未在 iOS 提供
  • 插件内已包含 UIBackgroundModes = audio 配置,但仍建议以正式构建结果为准做联调验证

Harmony

Harmony 端是应用内浮层,重点注意:

  • 仅支持 harmony-overlay-window + webview
  • 页面中必须挂载 <laoqianjunzi-float-host>
  • 不支持视频 PiP
  • bringAppToFront() 当前未提供

Web

Web 端能力用于调试和页面内预览,重点注意:

  • 仅支持 web-overlay-window + webview
  • 本质是 DOM/iframe 模拟层,不是系统浮窗
  • 不支持视频 PiP
  • 不支持 bringAppToFront()
  • 不存在系统悬浮权限概念

推荐接入流程

建议按这个顺序集成:

  1. 根据平台决定 mode
  2. checkSupportSync(mode, contentType)
  3. 组装 openOptions
  4. validateOpenOptionsSync(openOptions)
  5. 监听 onWindowEvent()onError()
  6. open()
  7. 页面销毁时按需 close()cleanupPageOwnedWindows()

这个顺序能明显减少“为什么没弹出来”“为什么某端能开某端不能开”的排障成本。

调试建议

  • 使用 setLogEnabled(true) 打开插件日志
  • requestId 按业务动作区分,便于串联事件
  • 每次 open() 之前先打印 checkSupportSync()validateOpenOptionsSync() 结果
  • Android 真机优先验证权限与基座是否为最新构建
  • iOS / Harmony / Web 如果窗口创建了但不显示,先检查页面宿主与生命周期清理逻辑

Demo 参考

插件内已经附带完整演示页,可直接查看:

  • uni_modules/laoqianjunzi-float/pages/index.uvue

演示页覆盖了:

  • 高阶网页浮层
  • 高阶视频 PiP
  • 原始 Native API
  • 支持性检查
  • 参数校验
  • 事件日志与错误日志

常见问题

1. Android 上 checkSupportSync() 提示缺少权限

先调用:

  • canDrawOverlaysSync()
  • openOverlayPermissionSettings()

用户授权后重新进入页面再试。

2. Android PiP 提示缺少 Manifest 宿主声明

通常不是插件文件缺失,而是原生声明还没有真正合并进当前运行包。请重新:

  • 构建自定义基座
  • 或重新打云包 / 安装包

3. iOS ios-in-app-float 打不开

先检查:

  • mode 是否写成 ios-in-app-float
  • contentType 是否为 webview
  • ownerPageId 是否传入且后续操作保持一致

4. Harmony 端没有看到浮层

优先检查页面里是否挂了:

  • <laoqianjunzi-float-host>

5. callJS() / updateFrame() 报错

通常有两类原因:

  • 当前窗口不存在
  • 当前模式或内容类型不支持这个动作

例如 PiP 窗口不能执行 callJS(),视频窗口也不能走 webview 的更新链路。

更新建议

如果你是新接入:

  • 直接用 getFloatingWindowManager()

如果你是历史项目迁移:

  • 保留 getNativeFloatManager() 也可以,但建议逐步迁移到高阶 API,后续维护成本更低

隐私、权限声明

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

android.permission.SYSTEM_ALERT_WINDOW

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

插件在不同平台创建原生浮球与信息卡片,并回传交互事件

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

许可协议

MIT协议

暂无用户评论。