更新记录
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 页面内模拟悬浮浮层
如果你要做的是“悬浮球 / 悬浮卡片 / 网页浮层 / 视频小窗 / 回到应用前台”这一类能力,这个插件可以直接接入。
功能概览
- 支持
webview与video-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 x:4.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
满足以下三者之一即可:
urlhtmlassetPath
常用字段如下:
| 字段 | 说明 |
|---|---|
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 |
附带数据 |
常见事件名包括:
openedclosedrefreshedframe-updatedjs-calledwebview-readywebview-errorframe-draggednative-close-requestrestore-requestedvideo-readyvideo-playedvideo-pausedvideo-seekedpip-enteredpip-refreshedrestored-to-appvideo-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。插件已自带权限声明,但你仍然要在业务侧处理授权流程:
- 调
canDrawOverlaysSync()判断 - 未授权时调
openOverlayPermissionSettings() - 用户返回后重新判断,再调用
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() - 不存在系统悬浮权限概念
推荐接入流程
建议按这个顺序集成:
- 根据平台决定
mode - 调
checkSupportSync(mode, contentType) - 组装
openOptions - 调
validateOpenOptionsSync(openOptions) - 监听
onWindowEvent()与onError() - 调
open() - 页面销毁时按需
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-floatcontentType是否为webviewownerPageId是否传入且后续操作保持一致
4. Harmony 端没有看到浮层
优先检查页面里是否挂了:
<laoqianjunzi-float-host>
5. callJS() / updateFrame() 报错
通常有两类原因:
- 当前窗口不存在
- 当前模式或内容类型不支持这个动作
例如 PiP 窗口不能执行 callJS(),视频窗口也不能走 webview 的更新链路。
更新建议
如果你是新接入:
- 直接用
getFloatingWindowManager()
如果你是历史项目迁移:
- 保留
getNativeFloatManager()也可以,但建议逐步迁移到高阶 API,后续维护成本更低

收藏人数:
https://gitee.com/laoqianjunzi/laoqianjunzi-float
下载插件并导入HBuilderX
下载示例项目ZIP
赞赏(0)
下载 1139
赞赏 2
下载 11941764
赞赏 1914
赞赏
京公网安备:11010802035340号