欢迎加入开源鸿蒙PC社区:
错误演示atomgit仓库地址: https://atomgit.com/gcw_7DJ1SfsY/InstallFailederrorfailedtoinstallbundle
修正演示atomgit仓库地址: https://atomgit.com/gcw_7DJ1SfsY/xiuzhengInstallFailederrorfailedtoinstallbundle

Install Failed: error: failed to install bundle.
code:9568289
error: install failed due to grant request permissions failed.
PermissionName: ohos.permission.SYSTEM_FLOAT_WINDOW
查看详细说明。
10:02:37.080: $ hdc shell rm -rf data/local/tmp/1dbe03e4e2b14f67974d6f097c89a684
10:02:37.082: Launch com.shili.pcerror failed, starting handle failure progress
以下操作中发生错误:部署Hap...
解决后正常编译:

一、问题背景
在鸿蒙PC应用开发中,创建子窗口(SubWindow)是一个常见需求。子窗口允许开发者创建独立于主窗口的浮动窗口,用于展示辅助内容、工具面板、设置对话框等。
然而,当我们在应用中声明并使用 ohos.permission.SYSTEM_FLOAT_WINDOW 权限时经常会遇到以下错误:
INSTALL_FAILED
error: failed to install bundle.
code:9568289
error: install failed due to grant request permissions failed.
PermissionName: ohos.permission.SYSTEM_FLOAT_WINDOW
这个错误导致应用无法安装到设备上,让许多开发者困惑不已。
二、错误分析
2.1 错误代码详解
| 错误代码 | 说明 |
|---|---|
| 9568289 | 权限申请失败 |
| 权限名称 | ohos.permission.SYSTEM_FLOAT_WINDOW |
2.2 权限类型分类
在鸿蒙系统中,权限可以分为两大类:
| 类型 | 说明 | 申请方式 | 示例 |
|---|---|---|---|
| 普通权限 | 不会直接涉及用户隐私或设备安全 | 静态声明即可 | 网络权限、蓝牙权限 |
| 敏感权限 | 涉及用户隐私或设备安全 | 需要用户授权 | 悬浮窗权限、定位权限 |
| 系统权限 | 涉及系统核心安全 | 需要特殊申请 | 强制安装权限、卸载应用 |
2.3 SYSTEM_FLOAT_WINDOW 权限分类
ohos.permission.SYSTEM_FLOAT_WINDOW 属于 敏感权限,需要用户显式授权。
但问题在于:应用的安装阶段无法弹出权限授予对话框,因此安装时会直接失败。
┌─────────────────────────────────────────────┐
│ 权限申请流程分析 │
├─────────────────────────────────────────────┤
│ │
│ 安装阶段 ────> 无法弹出UI授权对话框 ────> 安装失败 │
│ │
│ 运行阶段 ────> 可以弹出UI授权对话框 ────> 用户授权 │
│ │
└─────────────────────────────────────────────┘
三、常见错误写法
3.1 错误示例一:直接声明权限
json
// module.json5
{
"requestPermissions": [
{
"name": "ohos.permission.SYSTEM_FLOAT_WINDOW"
}
]
}
问题:缺少 reason 和 usedScene 字段,配置不完整。
3.2 错误示例二:usedScene 格式错误
json
// module.json5 - 错误写法
{
"requestPermissions": [
{
"name": "ohos.permission.SYSTEM_FLOAT_WINDOW",
"reason": "$string:permission_reason",
"usedScene": "$string:permission_used_scene" // ❌ 应该是对象
}
]
}
问题 :usedScene 必须是对象类型,不能是字符串。
3.3 正确格式
json
// module.json5 - 正确写法
{
"requestPermissions": [
{
"name": "ohos.permission.SYSTEM_FLOAT_WINDOW",
"reason": "$string:float_window_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
3.4 错误示例三:权限声明正确但安装仍然失败
即使 module.json5 配置正确,由于安装阶段无法弹出授权对话框,安装仍然会失败。
这是系统设计限制,不是配置错误。
四、解决方案
4.1 方案一:使用模拟子窗口(推荐)
既然悬浮窗权限在安装时无法授予,我们可以使用 UI 模拟的方式来实现类似效果。
原理 :使用 Stack 组件叠加层,模拟浮动窗口效果。
typescript
@Entry
@Component
struct SubWindowDemo {
@State subWindowCreated: boolean = false;
build() {
Stack() {
// 主内容
Column() {
Text('主内容')
}
.width('100%')
.height('100%')
// 模拟子窗口
if (this.subWindowCreated) {
Column() {
Text('模拟子窗口')
Button('关闭')
.onClick(() => {
this.subWindowCreated = false;
})
}
.width(300)
.height(200)
.position({ x: 100, y: 100 })
.shadow({
radius: 20,
color: 'rgba(0,0,0,0.3)'
})
}
}
}
}
优点:
- 无需申请权限
- 可以正常运行
- 实现简单的浮动效果
缺点:
- 不是真正的系统子窗口
- 无法像真实子窗口一样在桌面上自由拖动
- 无法超出应用窗口边界
4.2 方案二:动态请求权限(运行时授权)
在应用启动后,动态请求悬浮窗权限。
typescript
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { Permissions } from '@ohos.abilityAccessCtrl';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct SubWindowDemo {
createSubWindow(): void {
const context = getContext(this) as common.UIAbilityContext;
const atManager = abilityAccessCtrl.createAtManager();
// 请求悬浮窗权限
const permissions: Array<Permissions> = ['ohos.permission.SYSTEM_FLOAT_WINDOW'];
atManager.requestPermissionsFromUser(context, permissions)
.then((result) => {
if (result.authResults[0] === 0) {
// 权限获取成功,创建子窗口
this.doCreateSubWindow(context);
} else {
// 权限被拒绝
console.log('权限被拒绝');
}
})
.catch((err) => {
console.error('权限请求失败: ', err);
});
}
doCreateSubWindow(context: common.UIAbilityContext): void {
window.createWindow({
name: 'SubWindow',
windowType: 101, // APP_SUB_WINDOW
ctx: context
}).then((subWin) => {
subWin.resize(400, 300);
subWin.moveTo(200, 150);
subWin.loadContent('pages/SubWindowContent');
});
}
}
注意:这种方法在 DevEco Studio 直接运行时会失败,因为模拟器/设备不支持此权限。需要使用华为申请的企业签名。
4.3 方案三:申请企业签名(正式发布)
如果确实需要使用真实的悬浮窗功能,需要:
- 注册华为开发者账号并完成企业认证
- 申请悬浮窗权限的白名单
- 使用企业签名打包应用
申请流程:
1. 登录华为开发者联盟
2. 进入 "管理中心" > "应用市场"
3. 选择需要申请权限的应用
4. 进入 "能力申请" > "权限申请"
5. 找到 "SYSTEM_FLOAT_WINDOW" 权限
6. 提交申请并说明使用场景
7. 等待华为审核
4.4 方案四:使用系统预置权限
如果应用是系统应用(如华为内置应用),可以直接使用悬浮窗权限,无需额外申请。
五、权限配置详解
5.1 requestPermissions 字段说明
json
{
"requestPermissions": [
{
"name": "权限名称",
"reason": "权限申请原因(用于显示给用户)",
"usedScene": {
"abilities": ["涉及的Ability"],
"when": "使用时机"
}
}
]
}
5.2 usedScene.when 可选值
| 值 | 说明 |
|---|---|
always |
始终允许访问 |
inuse |
在使用期间允许访问 |
preinstall |
预安装时授权 |
5.3 权限申请场景示例
json
{
"requestPermissions": [
{
"name": "ohos.permission.SYSTEM_FLOAT_WINDOW",
"reason": "$string:float_window_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.INTERNET",
"reason": "$string:internet_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
]
}
六、常见问题排查
6.1 问题一:安装失败,错误码 9568289
原因:敏感权限在安装时无法授予。
解决:
- 如果不需要真实子窗口,使用模拟方案
- 如果需要真实子窗口,申请企业签名
6.2 问题二:权限申请返回 -1
原因:用户拒绝授权。
解决:向用户说明为什么需要此权限,引导用户开启。
6.3 问题三:权限申请后子窗口仍然创建失败
可能原因:
- 权限未真正授予(返回 -1)
- 子窗口名称重复
- 系统资源不足
排查步骤:
typescript
atManager.requestPermissionsFromUser(context, permissions)
.then((result) => {
console.log('权限结果: ', result.authResults[0]);
// 0 表示成功,-1 表示拒绝
});
6.4 问题四:子窗口创建成功但不显示
可能原因:
- 窗口位置超出屏幕
- 窗口大小为 0
- 未调用 show() 方法
解决:
typescript
subWin.resize(400, 300);
subWin.moveTo(200, 150);
subWin.show(); // 确保显示
七、最佳实践
7.1 权限申请规范
┌─────────────────────────────────────────────┐
│ 权限申请最佳实践 │
├─────────────────────────────────────────────┤
│ │
│ 1. 最小权限原则 │
│ └─ 只申请真正需要的权限 │
│ │
│ 2. 提前说明 │
│ └─ 在应用商店描述中说明权限用途 │
│ │
│ 3. 优雅降级 │
│ └─ 权限被拒绝时提供替代方案 │
│ │
│ 4. 运行时申请 │
│ └─ 在真正需要时才申请权限 │
│ │
└─────────────────────────────────────────────┘
7.2 子窗口管理规范
typescript
// ✅ 推荐:保存引用、主动销毁
private subWindow: window.Window | null = null;
aboutToDisappear(): void {
if (this.subWindow) {
this.subWindow.destroy();
this.subWindow = null;
}
}
// ❌ 错误:创建后不管理
createSubWindow(): void {
window.createWindow({...}); // 没有保存引用,无法销毁
}
7.3 错误处理规范
typescript
createSubWindow(): void {
window.createWindow({
name: 'SubWindow_' + Date.now(), // 使用唯一名称
windowType: 101,
ctx: context
})
.then((subWin) => {
// 成功处理
this.subWindow = subWin;
})
.catch((err) => {
// 错误处理
console.error('创建子窗口失败: ', err.code, err.message);
});
}
八、总结
核心要点
| 要点 | 说明 |
|---|---|
| 问题本质 | 敏感权限在安装时无法授予用户对话框 |
| 错误码 | 9568289 |
| 解决方案 | 使用模拟子窗口 / 申请企业签名 / 运行时动态申请 |
| 推荐方案 | UI 模拟(开发阶段)/ 企业签名(正式发布) |
代码检查清单
- module.json5 中权限配置格式正确
- usedScene 是对象类型,不是字符串
- 权限申请有合理的 reason 说明
- 实现了权限被拒绝时的降级处理
- 子窗口创建后保存了引用
- 页面销毁时主动销毁子窗口
权限申请流程图
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 开始 │ ──> │ 申请权限 │ ──> │ 权限结果 │
└─────────────┘ └─────────────┘ └─────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 结果=0 │ │ 结果=-1 │ │ 结果=-2 │
│ 成功 │ │ 被拒绝 │ │ 无权限 │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 创建子窗口 │ │ 提示用户 │ │ 企业签名 │
│ 继续执行 │ │ 手动授权 │ │ 或替代方案 │
└─────────────┘ └─────────────┘ └─────────────┘
通过本文的讲解,你应该已经理解了 9568289 权限申请失败的真正原因,并掌握了多种解决方案。在实际开发中,建议优先使用模拟子窗口方案,既可以快速验证功能,又避免了权限申请的复杂性。