Flutter三方库适配OpenHarmony【secure_application】— setWindowPrivacyMode 隐私模式实现
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net上一篇我们拿到了 Window 对象,这一篇讲怎么用它。是 OpenHarmony 提供的系统级隐私保护 API,开启后截屏、录屏都会变成黑屏,应用切换器中也看不到内容。这和 Android 的 FLAG_SECURE 效果一样,但 API 设计完全不同。本文详细讲解了API 特性:异步调
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
上一篇我们拿到了 Window 对象,这一篇讲怎么用它。setWindowPrivacyMode 是 OpenHarmony 提供的系统级隐私保护 API,开启后截屏、录屏都会变成黑屏,应用切换器中也看不到内容。这和 Android 的 FLAG_SECURE 效果一样,但 API 设计完全不同。
一、setWindowPrivacyMode API 详解
1.1 方法签名
setWindowPrivacyMode(isPrivacy: boolean): Promise<void>
| 参数 | 类型 | 说明 |
|---|---|---|
isPrivacy |
boolean | true=开启隐私模式,false=关闭 |
| 返回值 | Promise | 异步操作,成功时 resolve,失败时 reject |
1.2 调用示例
// 开启隐私模式
await this.mainWindow.setWindowPrivacyMode(true);
// 关闭隐私模式
await this.mainWindow.setWindowPrivacyMode(false);
1.3 系统行为
开启隐私模式后,系统会做以下处理:
| 行为 | 隐私模式关闭 | 隐私模式开启 |
|---|---|---|
| 用户截屏 | 正常截取内容 | 截取到黑屏 |
| 系统录屏 | 正常录制内容 | 录制到黑屏 |
| 应用切换器 | 显示App缩略图 | 显示黑屏/空白 |
| 投屏 | 正常投屏 | 投屏黑屏 |
| 辅助功能 | 可读取 | 部分受限 |
📌 这是系统级保护,不是应用层面的模拟。即使用 root 权限的工具也无法绕过。
二、applyPrivacyMode 实现
2.1 完整代码
private applyPrivacyMode(win: window.Window, isPrivacy: boolean): void {
try {
win.setWindowPrivacyMode(isPrivacy).then(() => {
Log.i(TAG, "Window privacy mode set to: " + isPrivacy);
}).catch((err: BusinessError) => {
Log.e(TAG, "Failed to set window privacy mode: " + JSON.stringify(err));
});
} catch (err) {
Log.e(TAG, "Exception applying privacy mode: " + JSON.stringify(err));
}
}
2.2 错误处理层次
applyPrivacyMode(win, true)
│
├── try-catch 外层
│ └── 捕获同步异常(如 win 对象无效)
│
└── Promise.then/catch 内层
├── then → 成功日志
└── catch → 异步错误日志
2.3 常见错误码
| 错误码 | 含义 | 处理方式 |
|---|---|---|
| 1300002 | 窗口状态异常 | 重新获取窗口 |
| 1300003 | 系统服务异常 | 延迟重试 |
| 1300004 | 权限不足 | 检查 PRIVACY_WINDOW 权限 |
三、setPrivacyMode 的完整调用链
3.1 从 Dart 到原生
Dart: controller.secure()
│
▼
Dart: SecureApplicationNative.secure()
│
▼
Dart: _channel.invokeMethod('secure')
│
▼ MethodChannel
│
Native: onMethodCall(call, result)
│ case "secure"
▼
Native: this.secured = true
Native: this.setPrivacyMode(true)
│
▼
Native: this.applyPrivacyMode(win, true)
│
▼
Native: win.setWindowPrivacyMode(true)
│
▼
系统:开启窗口隐私保护
3.2 setPrivacyMode 方法
private setPrivacyMode(isPrivacy: boolean): void {
if (this.mainWindow == null) {
// 窗口还没获取到,尝试重新获取
if (this.context != null) {
try {
window.getLastWindow(this.context).then((win: window.Window) => {
this.mainWindow = win;
this.applyPrivacyMode(win, isPrivacy);
}).catch((err: BusinessError) => {
Log.e(TAG, "Failed to get window for privacy mode: " + JSON.stringify(err));
});
} catch (err) {
Log.e(TAG, "Exception setting privacy mode: " + JSON.stringify(err));
}
}
return;
}
this.applyPrivacyMode(this.mainWindow, isPrivacy);
}
3.3 两条执行路径
| 路径 | 条件 | 行为 |
|---|---|---|
| 快速路径 | mainWindow != null | 直接调用 applyPrivacyMode |
| 慢速路径 | mainWindow == null | 先获取窗口,再调用 applyPrivacyMode |
四、ohos.permission.PRIVACY_WINDOW 权限
4.1 权限说明
| 属性 | 值 |
|---|---|
| 权限名 | ohos.permission.PRIVACY_WINDOW |
| 类型 | system_basic |
| 是否必须 | API 20 中可选 |
| 授权方式 | 静态声明 |
4.2 声明方式
在宿主应用的 module.json5 中声明:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.PRIVACY_WINDOW"
}
]
}
}
4.3 插件 vs 宿主应用的权限声明
| 位置 | 文件 | 是否生效 |
|---|---|---|
| 插件的 module.json5 | ohos/src/main/module.json5 | ⚠️ HAR 模块的权限声明可能不生效 |
| 宿主应用的 module.json5 | entry/src/main/module.json5 | ✅ 生效 |
💡 重要:权限应该在宿主应用中声明,而不是在插件中。插件的 README 应该告知开发者需要声明哪些权限。
4.4 不声明权限会怎样
在 API 20 的实际测试中,不声明 PRIVACY_WINDOW 权限也能正常调用 setWindowPrivacyMode。但这可能在未来的 API 版本中改变,所以建议还是声明。
五、隐私模式与 Android FLAG_SECURE 的对比
5.1 功能对比
| 功能 | Android FLAG_SECURE | OHOS setWindowPrivacyMode |
|---|---|---|
| 截屏防护 | ✅ | ✅ |
| 录屏防护 | ✅ | ✅ |
| 应用切换器 | ✅ 自动 | ✅ 自动 |
| API 类型 | 同步 | 异步 |
| 粒度 | 窗口级 | 窗口级 |
| 权限要求 | 无 | 可选 |
5.2 API 设计对比
// Android:同步,标志位操作
activity.window.addFlags(LayoutParams.FLAG_SECURE) // 开启
activity.window.clearFlags(LayoutParams.FLAG_SECURE) // 关闭
// OpenHarmony:异步,布尔值操作
await win.setWindowPrivacyMode(true) // 开启
await win.setWindowPrivacyMode(false) // 关闭
5.3 哪个设计更好
| 维度 | Android | OpenHarmony |
|---|---|---|
| 易用性 | ✅ 更简单 | 需要处理异步 |
| 错误处理 | ❌ 无法知道是否成功 | ✅ Promise 可以捕获错误 |
| 灵活性 | 标志位可以组合 | 单一布尔值 |
| 语义清晰度 | FLAG_SECURE 含义模糊 | ✅ PrivacyMode 含义明确 |
📌 OpenHarmony 的 API 设计更现代——异步操作、明确的错误处理、语义化的方法名。虽然用起来复杂一点,但更健壮。
六、隐私模式的开关时机
6.1 开启时机
case "secure":
this.secured = true;
this.setPrivacyMode(true); // Dart 层调用 secure() 时开启
result.success(true);
break;
6.2 关闭时机
case "open":
this.secured = false;
this.setPrivacyMode(false); // Dart 层调用 open() 时关闭
result.success(true);
break;
6.3 状态同步
Dart 层状态 原生层状态 系统状态
secured=true → this.secured=true → PrivacyMode=true
secured=false → this.secured=false → PrivacyMode=false
三层状态必须保持同步。如果出现不同步(比如原生端 setPrivacyMode 失败),用户可能以为保护已开启但实际上没有。
6.4 状态不同步的处理
// 理想方案:根据 setWindowPrivacyMode 的结果更新状态
win.setWindowPrivacyMode(isPrivacy).then(() => {
// 成功,状态已同步
Log.i(TAG, "Privacy mode synced: " + isPrivacy);
}).catch((err) => {
// 失败,通知 Dart 层
Log.e(TAG, "Privacy mode failed, notifying Dart");
// 可以通过 channel 通知 Dart 层保护未生效
});
当前实现选择了静默失败,但如果安全要求很高,可以在失败时通知 Dart 层。
七、实际测试验证
7.1 测试步骤
- 运行示例应用到 OpenHarmony 设备
- 点击 “secure” 按钮开启保护
- 尝试截屏 → 应该得到黑屏
- 按 Home 键查看应用切换器 → 应该看不到内容
- 点击 “open” 按钮关闭保护
- 再次截屏 → 应该正常截取
7.2 验证命令
# 查看日志确认隐私模式状态
hdc hilog | grep "Window privacy mode"
# 预期输出
# SecureApplicationPlugin: Window privacy mode set to: true
# SecureApplicationPlugin: Window privacy mode set to: false
7.3 常见测试问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 截屏仍然正常 | setWindowPrivacyMode 调用失败 | 检查日志中的错误信息 |
| 应用切换器仍显示内容 | 隐私模式未生效 | 确认窗口获取成功 |
| 调用报错 | API 版本不支持 | 确认 SDK 版本 >= API 20 |
总结
本文详细讲解了 setWindowPrivacyMode 的实现:
- API 特性:异步调用,布尔值控制,系统级保护
- 错误处理:双重 try-catch + Promise.catch
- 权限要求:PRIVACY_WINDOW 在 API 20 中可选,建议在宿主应用声明
- 与 FLAG_SECURE 对比:功能等价,API 设计更现代
- 状态同步:Dart 层、原生层、系统层三层状态保持一致
下一篇我们讲窗口事件监听——如何检测用户切换到其他应用。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- setWindowPrivacyMode 文档
- ohos.permission.PRIVACY_WINDOW
- Android FLAG_SECURE
- secure_application OpenHarmony 源码
- OpenHarmony 权限管理
- Promise 异步编程
- BusinessError 文档
- 开源鸿蒙跨平台社区

更多推荐


所有评论(0)