想做一个"小窗继续播放"的功能,调 window.createWindow 开悬浮窗,一直抛错。是我权限不够还是折叠屏不支持?
坐标和尺寸我用的是 windowRect,这个有讲究吗?
折叠屏上开悬浮窗失败,最高频的三个原因,按命中率排:
一、调用时机:createWindow 必须在 windowStage 就绪后调用——在 aboutToAppear 等页面早期生命周期里调,windowStage 还没就绪会直接失败。正确姿势是在 EntryAbility 的 onWindowStageCreate 里创建,或页面通过 getContext 拿到上下文且 windowStage 加载完成后再操作。
二、权限与设备策略:1)应用需要悬浮窗权限——设置里确认该应用的悬浮窗开关已打开;2)折叠屏展开态(大屏)上部分系统版本对第三方悬浮窗的尺寸、数量有策略限制,折叠态能开展开态失败的话,先怀疑设备策略。
三、参数问题:createWindow 的 type 必须是支持的类型(TYPE_FLOAT 等),name 不能重复(重复创建同名窗口会失败),尺寸不能超屏。展开态屏幕变大后,硬编码的窗口尺寸参数如果超界也会失败。
排查建议:把 createWindow 的 err 打出来看具体码——401 参数错、1300002 窗口已存在、1300003 系统服务异常,错误码不同修法不同。另外折叠态切换时窗口需要监听尺寸变化重新布局,不是一次性创建完事。
一句话收束:时机(windowStage 就绪后)、权限(悬浮窗开关)、参数(类型/重名/尺寸)三个方向查,错误码会告诉你具体是哪个。
可以打印错误码和创建参数:TYPE_FLOAT 需 SYSTEM_FLOAT_WINDOW 权限,201优先查授权,401查参数,801查能力支持,1300001查重复创建;
不能仅凭折叠屏就判断不支持。windowRect 的坐标、宽高是 px,写入默认使用 vp 的布局属性前要转换;开合后重新读取,别复用旧尺寸。
悬浮窗(自由窗口)能力对普通应用是受限的,先确认三件事:
① 能力层级
| 窗口模式 | 谁能用 |
|---|---|
| 全屏、分屏 | 普通应用(声明 supportWindowMode 即可) |
| 悬浮窗(自己创建独立小窗) | 通常需要系统应用权限,普通应用不可用 |
| 应用内"画中画"效果 | 用 PiPWindow/Window 的 PIP 模式(部分场景可用) |
| 系统级全局画中画 | 需系统权限 |
先确认你的目标能不能走"应用内小窗 + 悬浮抽屉"这条更实际的路:
// 用 Stack 在应用窗口内做一个可拖拽的小窗,不需要系统能力
Stack({ alignContent: Alignment.BottomEnd }) {
this.MainContent()
if (this.showFloat) {
Column() {
this.MiniPlayer()
}
.width(200)
.height(120)
.backgroundColor('#333')
.borderRadius(12)
.margin({ right: 16, bottom: 16 })
.gesture(PanGesture().onActionUpdate((e) => {
this.floatX += e.offsetX
this.floatY += e.offsetY
}))
}
}
② 如果是系统应用/已获权限,创建窗口的正确姿势
import { window } from '@kit.ArkUI'
const win = await window.createWindow({
name: 'float_win',
windowType: window.WindowType.TYPE_FLOAT,
ctx: context
})
// 尺寸不要用像素,用 vp 换算
await win.resize(vp2px(320), vp2px(480))
// 位置:折叠屏要基于"当前窗口可用区域"算,不能假设 (0,0) 是左上角
await win.moveWindowTo(vp2px(40), vp2px(80))
await win.setUIContent('pages/FloatPage')
await win.showWindow()
③ 常见失败原因排序
| 报错原因 | 排查 |
|---|---|
| 无窗口权限 | 是否为系统应用 / 是否申请了对应权限 |
| 窗口类型不支持 | TYPE_FLOAT 在小屏/折叠态可能被拒绝 |
| 尺寸超限 | 超出 maxWindowWidth 等约束 |
| 未在 UIAbility 上下文调用 | 必须传 Ability 的 context |
④ 折叠屏特有:悬浮窗在小屏(折叠态)上往往被系统转成全屏或分屏。要在 windowSizeChange 里做降级处理:小屏收起为底部迷你条,展开后再恢复浮窗。
给产品的替代方案:用"应用内悬浮球 + 迷你播放条" 实现 90% 的价值,开发成本低一个数量级,还不受系统限制。真要做全局小窗,那通常是系统应用或视频类白名单应用的战场。
折叠屏上开悬浮窗失败,最高频的三个原因,按命中率排:
一、调用时机:createWindow 必须在 windowStage 就绪后调用——在 aboutToAppear 等页面早期生命周期里调,windowStage 还没就绪会直接失败。正确姿势是在 EntryAbility 的 onWindowStageCreate 里创建,或页面通过 getContext 拿到上下文且 windowStage 加载完成后再操作。
二、权限与设备策略:1)应用需要悬浮窗权限——设置里确认该应用的悬浮窗开关已打开;2)折叠屏展开态(大屏)上部分系统版本对第三方悬浮窗的尺寸、数量有策略限制,折叠态能开展开态失败的话,先怀疑设备策略。
三、参数问题:createWindow 的 type 必须是支持的类型(TYPE_FLOAT 等);name 不能重复(重复创建同名窗口直接报错);窗口尺寸不能超屏——展开态屏幕变大后,硬编码的尺寸参数一般不会超,但折叠态和展开态切换时窗口需要监听尺寸变化重新布局,不是一次性创建完事。
排查建议:把 createWindow 的 err 完整打出来看错误码——参数错误、窗口已存在、系统服务异常对应不同修法;再确认 API 版本(window 模块部分接口有版本门槛)。
一句话收束:时机(windowStage 就绪后)、权限(悬浮窗开关)、参数(类型/重名/尺寸)三个方向查,createWindow 的错误码会告诉你具体是哪个。

