更新记录
2.0.3(2026-08-28)
更新说明文档
2.0.2(2026-08-28)
更新说明文档
2.0.1(2026-08-28)
- 移除通话模板内置接听/挂断(
callControl: 'builtin')及answerCall/endCallAPI - 接听/挂断请使用
aiko-call-recorder插件
平台兼容性
uni-app(4.23)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | √ | √ | √ | × | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
uni-app x(4.62)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | √ | × | × | × |
aiko-float-window
Android 全局浮窗 UTS 插件:基于系统叠加层(SYSTEM_ALERT_WINDOW),可在微信、视频播放器、系统通话界面等任意 App 上层显示浮窗。支持多实例、圆球 ⇄ 面板切换、拖动贴边、通话/微信/视频三套模板、WebView 自定义面板,以及系统通话与前台包名场景事件。
重要:插件只负责「画窗 + 抛事件」。是否弹出浮窗、弹出什么内容,均由宿主 App 自己决定。插件不会因场景事件自动
show。
平台支持
| 平台 | 支持 |
|---|---|
| App-Android | ✅ |
| uni-app(Vue2 / Vue3) | ✅ |
| uni-app x | ✅ |
| iOS | ❌ |
| 鸿蒙 | ❌ |
| 小程序 / Web | ❌ |
- 最低 Android API:21(Android 5.0)
- 推荐 HBuilderX:4.25+
- Vue 页面组件无法直接画进系统叠加层,必须通过本插件
安装与调试
- 将
uni_modules/aiko-float-window放入项目根目录 - HBuilderX → 运行 → 运行到手机或模拟器 → 制作自定义调试基座
- 使用自定义基座运行到 Android 真机
- 修改插件原生代码后,必须重新制作自定义基座才会生效
引入
uni-app x(UTS)
import * as floatWin from '@/uni_modules/aiko-float-window'
uni-app(JavaScript / TypeScript)
import * as floatWin from '@/uni_modules/aiko-float-window'
能力一览(v2)
| 能力 | 说明 |
|---|---|
| 系统浮窗 | 多实例圆球 ⇄ 面板,可拖动、松手贴边,每实例独立 id |
| 内置模板 | call 通话、wechat 微信、video 视频,由宿主在 show / update 指定 |
| WebView 自定义 | mode: 'webview',加载本地 HTML 或 https,支持 JS Bridge |
| 前台保活 | 有实例显示时自动拉起前台服务;全部 hide 后停止 |
| 场景事件 | 系统通话(高置信度)+ 前台包名(低置信度),不自动弹窗 |
| 按钮回调 | 自定义按钮、WebView 命令均回调宿主(接听/挂断请用 aiko-call-recorder) |
微信 / 视频场景说明:仅保证「相关 App 在前台」,不保证「正在微信通话」或「正在播放视频」。
推荐接入流程
1. 检查并申请悬浮窗权限(必须)
2. 检查并申请通知权限(show 后保活,强烈建议)
3. 申请运行时权限(电话状态、通知等)
4. registerListener 注册事件回调
5. (可选)开启使用情况访问 → setSceneDetector({ usage: true })
6. 宿主根据业务逻辑调用 show / update / hide
最小示例
import * as floatWin from '@/uni_modules/aiko-float-window'
// 1. 检查悬浮窗权限
floatWin.checkOverlayPermission((res) => {
const ok = res['data']?.['status'] === true
if (!ok) {
floatWin.toOverlayPermissionPage(() => {})
return
}
// 2. 注册监听(场景事件、按钮、WebView 命令)
floatWin.registerListener((evt) => {
if (evt['code'] !== 0) return
const data = evt['data']
if (data?.['type'] === 'scene' && data['scene'] === 'call') {
// 宿主决定是否弹出
floatWin.show({
template: 'call',
title: '系统通话',
number: data['phoneNumber'] as string,
state: data['callState'] as number
}, () => {})
}
})
// 3. 主动显示浮窗
floatWin.show({
mode: 'template',
template: 'call',
title: '系统通话',
subtitle: '客户 A',
number: '10086',
state: 2,
buttons: [{ id: 'note', text: '备注' }]
}, (res) => {
console.log(res)
})
})
权限说明
插件已在 AndroidManifest.xml 中声明以下权限,宿主需在隐私政策中说明用途:
| 权限 | 用途 | 是否必须 |
|---|---|---|
SYSTEM_ALERT_WINDOW |
显示在其他 App 上层 | 必须 |
POST_NOTIFICATIONS |
前台服务通知(保活) | 强烈建议 |
FOREGROUND_SERVICE / SPECIAL_USE |
后台保持浮窗 | show 时自动使用 |
READ_PHONE_STATE |
监听系统通话状态 | 场景事件需要 |
PACKAGE_USAGE_STATS |
检测前台 App 包名 | 微信/视频场景需要 |
权限相关 API
| 方法 | 说明 | 成功时 data |
|---|---|---|
checkOverlayPermission |
是否已授予悬浮窗 | { status: boolean } |
toOverlayPermissionPage |
跳转系统悬浮窗设置 | { status: boolean } |
isForegroundPermission |
通知是否已开启 | { status: boolean } |
toForegroundPage |
跳转通知设置 | { status: boolean } |
checkUsageStatsPermission |
使用情况访问是否已开 | { status: boolean } |
toUsageStatsPermissionPage |
跳转使用情况访问设置 | { status: boolean } |
requestPermissions |
申请运行时权限数组 | 见下方说明 |
requestPermissions 示例:
floatWin.requestPermissions([
'android.permission.READ_PHONE_STATE',
'android.permission.POST_NOTIFICATIONS'
], (res) => {
// code === 0:已全部授权
// code !== 0:仍有未授权项,data.grantedList 为待授权列表
})
统一回调格式
所有 API 均通过回调返回:
{
"code": 0,
"message": "",
"data": {}
}
code === 0:成功code !== 0:失败,message为错误说明
错误码
| code | 含义 |
|---|---|
0 |
成功 |
-1 |
通用失败(Context 不可用、跳转失败、显示异常等) |
-2 |
未授予悬浮窗权限 |
-3 |
WebView 地址不合法(仅允许本地 HTML / file / https) |
-4 |
浮窗未显示(update / expand / collapse 时) |
-5 |
未授予使用情况访问权限 |
v2:多实例浮窗
通过 id 区分多个独立浮窗,互不覆盖。不传 id 时默认为 default(与 v1 单实例行为兼容)。
// 实例 A:微信模板
floatWin.show({
id: 'float-a',
template: 'wechat',
title: '微信跟进',
ballText: 'A',
y: 120
}, () => {})
// 实例 B:视频模板,置顶显示
floatWin.show({
id: 'float-b',
template: 'video',
title: '视频备注',
ballText: 'B',
y: 220,
bringToFront: true
}, () => {})
// 关闭指定实例
floatWin.hideById({ id: 'float-a' }, () => {})
// 关闭全部
floatWin.hideAll(() => {})
// 查询所有实例
floatWin.isShowing((res) => {
const data = res['data']
const list = data['instances'] // 数组
const count = data['count']
})
update 通过 id 字段指定目标实例:
floatWin.update({ id: 'float-b', meta: '更新内容' }, () => {})
floatWin.expandById({ id: 'float-a' }, () => {})
floatWin.collapseById({ id: 'float-a' }, () => {})
关闭 / 展开 / 收起 default 实例可直接用无 id 版本:
floatWin.hide(() => {})
floatWin.expand(() => {})
floatWin.collapse(() => {})
浮窗 API
| 方法 | 说明 |
|---|---|
show(options, callback) |
显示浮窗(圆球或面板) |
hide(callback) |
关闭浮窗并停止前台服务 |
update(options, callback) |
更新已显示浮窗的内容(增量合并) |
expand(callback) |
展开为面板 |
collapse(callback) |
收起为圆球 |
isShowing(callback) |
查询状态 |
isShowing 成功时 data 字段:
{
"showing": true,
"expanded": false,
"template": "call",
"mode": "template",
"x": 0,
"y": 120
}
交互说明
- 单击圆球:展开面板
- 拖动圆球 / 面板标题区:移动位置,松手后自动贴左右边
- 面板「收起」:收为圆球
- 圆球文字:
ballText,默认按模板显示「通 / 微 / 视」 - 角标:
badge非空时显示在圆球右上角
show / update 参数(FloatShowOptions)
通用字段
| 字段 | 类型 | 说明 |
|---|---|---|
mode |
string |
template(默认)或 webview |
template |
string |
call / wechat / video,由宿主指定 |
expanded |
boolean |
true 直接展开面板,默认 false 为圆球 |
title |
string |
主标题 |
subtitle |
string |
副标题 |
meta |
string |
辅助信息行 |
avatar |
string |
本地头像路径(远程 URL v1 忽略) |
buttons |
Array<{id,text}> |
操作按钮,最多 3 个 |
ballText |
string |
圆球显示文字(取前 2 字) |
badge |
string |
圆球角标 |
notifyTitle |
string |
前台服务通知标题 |
notifyContent |
string |
前台服务通知内容 |
id |
string |
v2 实例 ID,默认 default |
x / y |
number |
v2 初始坐标 |
bringToFront |
boolean |
v2 显示时置顶 |
通话模板 template: 'call'
| 字段 | 类型 | 说明 |
|---|---|---|
number |
string |
号码 |
state |
number \| string |
0 空闲 / 1 响铃 / 2 通话中 |
durationMs |
number |
通话时长(毫秒),面板显示为 分:秒 |
微信模板 template: 'wechat'
| 字段 | 类型 | 说明 |
|---|---|---|
nickname |
string |
昵称 |
kind |
string |
audio 语音 / video 视频 / unknown 未知 |
视频模板 template: 'video'
| 字段 | 类型 | 说明 |
|---|---|---|
appName |
string |
App 名称 |
contentTitle |
string |
内容标题 |
WebView 模式 mode: 'webview'
| 字段 | 类型 | 说明 |
|---|---|---|
html |
string |
内联 HTML,写入缓存后以 file 协议路径加载 |
url |
string |
支持 https、file 协议 URL,或本地绝对路径 |
安全限制:仅允许本地 HTML、file 协议、绝对路径、https。明文 http 与 javascript 协议会被拒绝(code = -3)。
update 合并规则
update只合并本次传入的非空字段,未传字段保留原值- 适合通话计时、状态变更等场景:
floatWin.update({
durationMs: 60000,
state: 2,
meta: '已通话 60 秒'
}, () => {})
提示:可选字段请勿显式传
null,否则可能被序列化为 JSON null。插件已做过滤,但建议只传需要更新的字段。
三套模板示例
通话
floatWin.show({
mode: 'template',
template: 'call',
title: '系统通话',
subtitle: '客户 A',
meta: '销售跟进',
number: '10086',
state: 2,
durationMs: 0,
ballText: '通',
buttons: [
{ id: 'note', text: '备注' },
{ id: 'crm', text: '客户' }
],
notifyTitle: '全局浮窗运行中',
notifyContent: '通话中'
}, () => {})
微信
floatWin.show({
mode: 'template',
template: 'wechat',
title: '微信通话',
subtitle: '好友',
nickname: '张三',
kind: 'video',
ballText: '微',
buttons: [{ id: 'note', text: '备注' }]
}, () => {})
视频
floatWin.show({
mode: 'template',
template: 'video',
title: '正在播放',
appName: '腾讯视频',
contentTitle: '演示影片',
ballText: '视',
buttons: [{ id: 'fav', text: '收藏' }]
}, () => {})
WebView 自定义与 Bridge
显示 WebView 面板
const html = `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<style>
body { font-family: sans-serif; padding: 12px; }
button { width: 100%; padding: 8px; margin-top: 8px; }
</style>
</head>
<body>
<h3 id="title">自定义浮窗</h3>
<p id="sub">Bridge 与宿主通信</p>
<button onclick="AikoFloat.post(JSON.stringify({id:'ping',command:'ping'}))">
向宿主发 ping
</button>
<pre id="meta"></pre>
<script>
window.__AIKO_FLOAT_PUSH = function (json) {
document.getElementById('meta').textContent = json
try {
var d = JSON.parse(json)
if (d.title) document.getElementById('title').textContent = d.title
if (d.subtitle) document.getElementById('sub').textContent = d.subtitle
} catch (e) {}
}
</script>
</body>
</html>`
floatWin.show({
mode: 'webview',
template: 'call',
title: '自定义功能',
html: html,
expanded: true
}, () => {})
页面 → 宿主(AikoFloat.post)
AikoFloat.post(JSON.stringify({
id: 'save', // 按钮/命令 ID
command: 'save' // 可选,与 id 二选一
}))
宿主在 registerListener 中收到 type: 'webview' 事件:
{
"type": "webview",
"command": "save",
"buttonId": "save",
"template": "call",
"payload": { "id": "save", "command": "save" }
}
宿主 → 页面(update 推送)
调用 update 后,插件会执行:
window.__AIKO_FLOAT_PUSH && window.__AIKO_FLOAT_PUSH('{"title":"新标题",...}')
事件监听
| 方法 | 说明 |
|---|---|
registerListener(callback) |
注册统一事件回调 |
unRegisterListener(callback) |
取消监听并停止场景检测 |
isRegisterListener(callback) |
是否已注册 |
事件类型(data.type)
| type | 触发时机 |
|---|---|
registered |
registerListener 成功 |
scene |
通话状态或前台包名变化 |
button |
用户点击模板按钮 |
webview |
网页调用 AikoFloat.post |
overlay |
浮窗显示/隐藏/展开/收起/拖动 |
场景事件(type = scene)
| 字段 | 说明 |
|---|---|
scene |
call / wechat / video / other / idle |
source |
telephony(系统通话)/ usage(前台包名) |
confidence |
high(通话)/ low(包名) |
callState |
0 空闲 / 1 响铃 / 2 通话中(仅 telephony) |
phoneNumber |
来电号码(Android 12+ 可能为空) |
packageName |
前台包名(仅 usage) |
浮窗事件(type = overlay)
action 取值:shown / hidden / expanded / collapsed / moved
按钮事件(type = button)
{
"type": "button",
"buttonId": "note",
"template": "call",
"payload": { "...": "当前 show 时的完整参数" }
}
宿主自动弹窗示例
插件不会自动 show,以下为推荐写法:
floatWin.registerListener((res) => {
if (res['code'] !== 0) return
const data = res['data']
if (data?.['type'] !== 'scene') return
const scene = data['scene'] as string
if (scene === 'call') {
const callState = data['callState'] as number
if (callState === 0) {
floatWin.hide(() => {})
return
}
floatWin.show({
template: 'call',
title: '系统通话',
number: data['phoneNumber'] as string,
state: callState,
buttons: [{ id: 'note', text: '备注' }]
}, () => {})
} else if (scene === 'wechat') {
floatWin.show({
template: 'wechat',
title: '微信在前台',
subtitle: '低置信度,不代表正在通话',
kind: 'unknown'
}, () => {})
} else if (scene === 'video') {
floatWin.show({
template: 'video',
title: '视频 App 在前台',
appName: data['packageName'] as string,
contentTitle: '低置信度'
}, () => {})
}
})
场景检测与包名规则
| 方法 | 说明 |
|---|---|
setSceneDetector(options, callback) |
开关检测能力 |
getSceneDetector(callback) |
查询当前配置 |
setPackageRules(options, callback) |
增删微信/视频包名 |
getPackageRules(callback) |
查询包名列表 |
setSceneDetector
// 默认 telephony = true,usage = false
floatWin.setSceneDetector({
telephony: true, // 系统通话(高置信度)
usage: true // 前台包名(低置信度,需先开使用情况访问)
}, (res) => {
// 成功 data: { telephony, usage, telephonyRunning, usageRunning }
})
setPackageRules
内置微信:com.tencent.mm
内置视频(部分):爱奇艺、腾讯视频、优酷、哔哩哔哩、芒果 TV、YouTube、西瓜视频等。
// 添加自定义视频 App
floatWin.setPackageRules({
addVideo: ['com.example.player'],
removeVideo: ['tv.danmaku.bili'],
addWechat: ['com.tencent.mm'],
reset: false // true 时清空所有自定义规则
}, () => {})
// 查询
floatWin.getPackageRules((res) => {
// data.wechat / data.video / data.builtinWechat / data.builtinVideo
})
与 aiko-call-recorder 的关系
两个插件互不依赖,可单独使用:
| 插件 | 职责 |
|---|---|
aiko-float-window |
系统浮窗 UI + 场景信号 |
aiko-call-recorder |
通话录音、短信监听、联系人等 |
接听、挂断、录音请使用通话插件;本插件只负责窗口展示与场景事件。
常见问题
1. 切到微信后浮窗消失
- 检查是否已授予通知权限(前台服务保活)
- 部分 ROM 会激进杀后台,需在系统设置中允许 App 后台运行
- 检查厂商是否有「悬浮窗」第二层开关
2. show 失败,code = -2
未授予悬浮窗权限。先调用 toOverlayPermissionPage 引导用户开启「显示在其他应用上层」。
3. 没有微信 / 视频场景事件
- 调用
toUsageStatsPermissionPage开启「使用情况访问」 setSceneDetector({ usage: true })- 确认目标 App 包名在规则列表中(可用
setPackageRules添加)
包名命中仅表示该 App 在前台,不代表正在通话或播放。
4. 面板显示 "null" 文字
请升级至最新版本。旧版在可选字段未赋值时可能显示 JSON null;新版已过滤空值。接入时建议 update 只传需要变更的字段。
5. 修改插件代码后无效果
UTS 原生插件必须重新制作自定义调试基座,普通热更新不会生效。
6. 全屏视频上看不到浮窗
部分播放器全屏时会压制叠加层,属于系统/ROM 限制,插件无法保证 100% 覆盖。
7. Android 12+ 来电号码为空
系统对 READ_PHONE_STATE 限制更严,号码字段可能为空,请结合业务做降级处理。
合规与上架提示
- 悬浮窗会覆盖在其他 App 上层,必须在隐私政策中告知用户用途,并取得明确同意
- 请勿用于诱导点击、未告知的监控等违规场景
- 应用商店上架时需申报悬浮窗、电话状态、使用情况访问等敏感权限
- 插件不采集、不上传任何用户数据
法律免责声明
购买、下载、集成或使用本插件,即视为已阅读并同意本声明。不同意请立即停止使用并卸载。
-
工具性质
本插件仅为 Android 技术组件(系统叠加层浮窗、场景事件回调),按「现状(AS IS)」提供。插件作者及权利人不对任何具体业务场景作出许可、背书或保证,也不因提供本插件而与最终用户形成服务关系。 -
使用者全责
集成方(购买者、开发者、运营方)对其最终 App 的产品设计、权限申请、隐私政策、用户告知与同意、应用商店申报、以及实际用途承担全部法律责任。是否弹出浮窗、弹出何种内容、如何处理场景事件,均由宿主自行决定;插件不自动show,也不内置接听、挂断或跳转。 -
合法合规义务
使用本插件须遵守所在司法辖区的法律法规及监管要求(包括但不限于《中华人民共和国个人信息保护法》《网络安全法》《反不正当竞争法》及相关通信、广告、消费者保护规定),以及各应用商店、操作系统的政策。涉及覆盖其他 App、读取电话状态、使用情况访问等敏感能力时,必须向用户显著告知用途并取得明确同意,不得超范围处理个人信息。 -
禁止用途
严禁将本插件用于:未经授权的监控或窃听、窃取隐私、诱导点击、骚扰、诈骗、侵犯他人合法权益,或任何违法、违规、侵害第三方权益的场景。因违规使用产生的行政处罚、民事赔偿、刑事责任及其他后果,均由使用者自行承担。 -
能力与兼容性无担保
场景检测(尤其是基于前台包名的微信/视频判断)不保证准确;不同 ROM、系统版本、厂商策略可能导致浮窗被压制、权限不可用或事件缺失。插件作者不保证本插件在任何设备上完全可用、持续可用或满足特定目的。 -
责任限制
在法律允许的最大范围内,插件作者及权利人对因购买、集成、使用、无法使用或滥用本插件而导致的任何直接、间接、附带、惩罚性损失(包括但不限于利润损失、数据丢失、商誉损害、行政处罚、第三方索赔),不承担任何责任。即使事先知悉发生此类损失的可能性,亦同。 -
第三方与上架风险
最终 App 能否通过应用商店审核、是否被系统限制悬浮窗或相关权限,取决于商店政策与设备环境,与本插件销售无关。因上架被拒、功能受限或第三方投诉引起的损失,由集成方自行承担。 -
声明效力
本声明构成插件授权与使用条件的一部分。若部分条款被认定无效,不影响其余条款效力。插件作者有权更新本声明,更新后以插件文档最新版本为准。
授权与技术支持
- DCloud 插件市场购买后:
interface.uts明文;index.uts与 Kotlin 实现加密 - 授权绑定购买者
appid与 Android 包名
更新日志
技术支持 · 商务咨询
AI解决方案-AIKO王 · 广东 深圳
微信扫码添加,获取技术支持与授权咨询

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 15
赞赏 0
下载 12541443
赞赏 1947
赞赏
京公网安备:11010802035340号