Flutter三方库适配OpenHarmony【secure_application】— Android 端 FLAG_SECURE 实现分析
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net在动手写 OpenHarmony 的原生代码之前,先看看 Android 端是怎么做的。Android 的实现是所有平台中最"硬核"的——它用了系统级的窗口标志,能真正阻止截屏和录屏。OpenHarmony 的和它的思路非常相似,所以理解 Android 的实现对我们的适配工作很有参考价值
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
在动手写 OpenHarmony 的原生代码之前,先看看 Android 端是怎么做的。Android 的实现是所有平台中最"硬核"的——它用了系统级的 FLAG_SECURE 窗口标志,能真正阻止截屏和录屏。OpenHarmony 的 setWindowPrivacyMode 和它的思路非常相似,所以理解 Android 的实现对我们的适配工作很有参考价值。
一、Android 插件类结构
1.1 类声明与接口
class SecureApplicationPlugin : FlutterPlugin, MethodCallHandler,
ActivityAware {
private var channel: MethodChannel? = null
private var activity: Activity? = null
private var secured = false
}
实现了三个接口:
| 接口 | 作用 |
|---|---|
FlutterPlugin |
插件生命周期管理 |
MethodCallHandler |
处理 Dart 层的方法调用 |
ActivityAware |
获取 Activity 引用 |
1.2 与 OpenHarmony 的接口对比
| Android | OpenHarmony | 说明 |
|---|---|---|
| FlutterPlugin | FlutterPlugin | 完全对应 |
| MethodCallHandler | MethodCallHandler | 完全对应 |
| ActivityAware | 不需要 | OHOS 通过 ApplicationContext 获取窗口 |
💡 关键差异:Android 需要 ActivityAware 来获取 Activity 的 Window 对象,而 OpenHarmony 通过
FlutterPluginBinding.getApplicationContext()就能获取窗口。这是两个平台在架构上的本质区别。
二、FLAG_SECURE 窗口标志
2.1 什么是 FLAG_SECURE
FLAG_SECURE 是 Android 的一个窗口标志位,定义在 WindowManager.LayoutParams 中:
// 添加 FLAG_SECURE
activity?.window?.addFlags(LayoutParams.FLAG_SECURE)
// 移除 FLAG_SECURE
activity?.window?.clearFlags(LayoutParams.FLAG_SECURE)
2.2 FLAG_SECURE 的效果
| 行为 | FLAG_SECURE=false | FLAG_SECURE=true |
|---|---|---|
| 截屏 | ✅ 正常截屏 | ❌ 截屏为黑屏 |
| 录屏 | ✅ 正常录屏 | ❌ 录屏为黑屏 |
| 应用切换器 | 显示App内容 | 显示空白/黑屏 |
| Chromecast投屏 | 正常投屏 | 投屏为黑屏 |
| 辅助功能 | 可读取内容 | 部分受限 |
2.3 系统级保护的意义
FLAG_SECURE 是操作系统级别的保护,不是应用层面的模拟。这意味着:
- 即使用 root 权限的截屏工具也无法截取内容
- 系统的应用切换器会自动隐藏内容
- 不需要应用自己画遮罩来隐藏内容
📌 对比:iOS 没有类似 FLAG_SECURE 的机制,所以 iOS 端需要自己创建一个原生的模糊视图来遮挡内容。OpenHarmony 的
setWindowPrivacyMode提供了和 FLAG_SECURE 类似的系统级保护。
三、onMethodCall 方法处理
3.1 方法分发
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"secure" -> {
secured = true
activity?.window?.addFlags(LayoutParams.FLAG_SECURE)
result.success(true)
}
"open" -> {
secured = false
activity?.window?.clearFlags(LayoutParams.FLAG_SECURE)
result.success(true)
}
"lock" -> {
result.success(true)
}
"unlock" -> {
result.success(true)
}
"opacity" -> {
result.success(true)
}
else -> result.notImplemented()
}
}
3.2 各方法的原生行为
| 方法 | Android 行为 | 说明 |
|---|---|---|
secure |
addFlags(FLAG_SECURE) | 开启截屏防护 |
open |
clearFlags(FLAG_SECURE) | 关闭截屏防护 |
lock |
空实现 | 锁定由 Dart 层处理 |
unlock |
空实现 | 解锁由 Dart 层处理 |
opacity |
空实现 | 模糊遮罩由 Flutter Widget 处理 |
💡 设计洞察:Android 端只有
secure和open有实际的原生操作,其他三个方法都是空实现。这说明 Android 端的核心职责就是控制 FLAG_SECURE 标志位,其他逻辑都在 Dart 层。
四、ActivityAware 生命周期
4.1 Activity 引用管理
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivity() {
activity = null
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivityForConfigChanges() {
activity = null
}
4.2 四个生命周期回调
| 回调 | 触发时机 | 操作 |
|---|---|---|
| onAttachedToActivity | 插件绑定到 Activity | 保存 Activity 引用 |
| onDetachedFromActivity | 插件从 Activity 解绑 | 清空 Activity 引用 |
| onReattachedToActivityForConfigChanges | 配置变更后重新绑定 | 更新 Activity 引用 |
| onDetachedFromActivityForConfigChanges | 配置变更前解绑 | 清空 Activity 引用 |
4.3 为什么需要 Activity
Android 的窗口标志位是挂在 Activity 的 Window 上的:
activity?.window?.addFlags(LayoutParams.FLAG_SECURE)
// ↑ ↑
// Activity Window
没有 Activity 引用就无法操作窗口。这也是为什么 Android 端需要实现 ActivityAware 接口。
4.4 OpenHarmony 的不同之处
OpenHarmony 获取窗口不需要 Ability 引用:
// OpenHarmony:通过 ApplicationContext 获取窗口
window.getLastWindow(this.context).then((win) => {
this.mainWindow = win;
});
// Android:通过 Activity 获取窗口
activity?.window?.addFlags(...)
这个差异决定了 OpenHarmony 端不需要实现 AbilityAware 接口。
五、Android 端的应用切换器处理
5.1 FLAG_SECURE 的自动效果
在 Android 上,一旦设置了 FLAG_SECURE,系统会自动在应用切换器中隐藏内容。不需要应用做任何额外处理。
用户按 Home 键
│
├── FLAG_SECURE = true → 应用切换器显示空白
└── FLAG_SECURE = false → 应用切换器显示正常内容
5.2 与 Dart 层的配合
虽然 FLAG_SECURE 自动处理了应用切换器,但 Dart 层的 SecureGate 模糊遮罩仍然需要工作。因为:
- 用户回到 App 时,FLAG_SECURE 不会阻止用户看到内容
- 需要 SecureGate 的模糊遮罩来遮挡内容,直到用户认证通过
用户切回 App
│
├── Android 原生层:FLAG_SECURE 仍然生效(防截屏)
└── Flutter Dart 层:SecureGate 显示模糊遮罩(防偷看)
│
└── onNeedUnlock → 认证 → authSuccess → 移除遮罩
六、Android 端的局限性
6.1 FLAG_SECURE 的副作用
| 副作用 | 影响 | 能否规避 |
|---|---|---|
| 无法截屏 | 用户自己也不能截屏 | ❌ 这是设计意图 |
| 无法录屏 | 用户自己也不能录屏 | ❌ 这是设计意图 |
| 无法投屏 | Chromecast 等投屏黑屏 | ❌ 系统限制 |
| 辅助功能受限 | 部分无障碍服务受影响 | ⚠️ 需要权衡 |
6.2 用户体验考量
有些用户可能需要截屏来保存信息(比如保存交易记录)。如果一直开着 FLAG_SECURE,用户体验会受影响。
secure_application 的设计允许动态开关:
// 需要保护时开启
controller.secure();
// 不需要保护时关闭(允许截屏)
controller.open();
6.3 对 OpenHarmony 适配的启示
setWindowPrivacyMode也有类似的副作用,需要在文档中说明- 动态开关机制在 OpenHarmony 上同样适用
- 应该在
open()时及时关闭隐私模式,避免不必要的限制
七、从 Android 到 OpenHarmony 的映射
7.1 API 映射表
| Android | OpenHarmony | 说明 |
|---|---|---|
addFlags(FLAG_SECURE) |
setWindowPrivacyMode(true) |
开启隐私保护 |
clearFlags(FLAG_SECURE) |
setWindowPrivacyMode(false) |
关闭隐私保护 |
activity.window |
window.getLastWindow(context) |
获取窗口对象 |
ActivityAware |
不需要 | 获取窗口的方式不同 |
| 自动处理应用切换器 | 自动处理应用切换器 | 系统级行为 |
7.2 需要额外实现的部分
Android 端没有做但 OpenHarmony 端需要做的:
- 窗口事件监听:监听
WINDOW_INACTIVE事件,通知 Dart 层锁定 - 应用生命周期回调:监听前后台切换,通知 Dart 层锁定
- 窗口异步获取:
getLastWindow是异步的,需要处理获取失败的情况
这些额外的工作是因为 OpenHarmony 的事件模型和 Android 不完全相同,后续文章会详细讲解。
总结
本文分析了 secure_application 的 Android 端实现:
- FLAG_SECURE:系统级截屏/录屏防护,一行代码开关
- ActivityAware:通过 Activity 获取 Window 对象
- 方法处理:只有 secure/open 有原生操作,其他空实现
- 自动效果:FLAG_SECURE 自动处理应用切换器内容隐藏
- 映射关系:FLAG_SECURE → setWindowPrivacyMode,思路一致
下一篇我们分析 iOS 端的实现——它走了一条完全不同的路,用原生 UIVisualEffectView 来遮挡内容。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- Android FLAG_SECURE 文档
- Android ActivityAware 接口
- Android Window 类
- secure_application Android 源码
- OpenHarmony setWindowPrivacyMode
- Flutter Plugin Android 开发
- Kotlin 语言指南
- 开源鸿蒙跨平台社区

Android 端 FLAG_SECURE 开启后应用切换器中的效果
更多推荐



所有评论(0)