前言

欢迎加入开源鸿蒙跨平台社区: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 是操作系统级别的保护,不是应用层面的模拟。这意味着:

  1. 即使用 root 权限的截屏工具也无法截取内容
  2. 系统的应用切换器会自动隐藏内容
  3. 不需要应用自己画遮罩来隐藏内容

📌 对比: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 端只有 secureopen 有实际的原生操作,其他三个方法都是空实现。这说明 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 模糊遮罩仍然需要工作。因为:

  1. 用户回到 App 时,FLAG_SECURE 不会阻止用户看到内容
  2. 需要 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 适配的启示

  1. setWindowPrivacyMode 也有类似的副作用,需要在文档中说明
  2. 动态开关机制在 OpenHarmony 上同样适用
  3. 应该在 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 端需要做的:

  1. 窗口事件监听:监听 WINDOW_INACTIVE 事件,通知 Dart 层锁定
  2. 应用生命周期回调:监听前后台切换,通知 Dart 层锁定
  3. 窗口异步获取getLastWindow 是异步的,需要处理获取失败的情况

这些额外的工作是因为 OpenHarmony 的事件模型和 Android 不完全相同,后续文章会详细讲解。

总结

本文分析了 secure_application 的 Android 端实现:

  1. FLAG_SECURE:系统级截屏/录屏防护,一行代码开关
  2. ActivityAware:通过 Activity 获取 Window 对象
  3. 方法处理:只有 secure/open 有原生操作,其他空实现
  4. 自动效果:FLAG_SECURE 自动处理应用切换器内容隐藏
  5. 映射关系:FLAG_SECURE → setWindowPrivacyMode,思路一致

下一篇我们分析 iOS 端的实现——它走了一条完全不同的路,用原生 UIVisualEffectView 来遮挡内容。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Android 应用切换器效果
Android 端 FLAG_SECURE 开启后应用切换器中的效果

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐