前言

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

iOS 没有 Android 那样的 FLAG_SECURE 机制,无法从系统层面阻止截屏。所以 iOS 端走了一条完全不同的路——在应用即将进入后台时,用原生 UIVisualEffectView 创建一个模糊视图覆盖在整个 App 上方,让应用切换器中看到的是模糊画面。

这种方案和 OpenHarmony 的 setWindowPrivacyMode 有本质区别,但理解它有助于我们全面认识各平台的隐私保护策略。

一、iOS 的隐私保护机制

1.1 iOS 应用切换器的行为

iOS 在用户按 Home 键或上滑时,会对当前 App 做一次快照(snapshot),这个快照会显示在应用切换器中。

用户按 Home 键
    │
    ├── iOS 系统对当前界面截图
    ├── 截图保存为应用切换器缩略图
    └── App 进入后台

1.2 为什么 iOS 不能用 FLAG_SECURE

特性 Android iOS
系统级截屏防护 ✅ FLAG_SECURE ❌ 不支持
应用切换器快照控制 自动(FLAG_SECURE) 需要手动遮挡
第三方截屏工具防护
录屏防护

iOS 的设计哲学是用户拥有设备的完全控制权,不允许 App 阻止用户截屏。所以只能用"遮挡"的方式来保护内容。

1.3 iOS 端的保护策略

App 即将进入非活跃状态 (applicationWillResignActive)
    │
    └── 添加 UIVisualEffectView(模糊视图)到 Window 上方
            │
App 回到活跃状态 (applicationDidBecomeActive)
    │
    └── 延迟 500ms 后移除 UIVisualEffectView

二、UIVisualEffectView 模糊视图

2.1 创建模糊视图

let blurEffect = UIBlurEffect(style: .light)
let blurView = UIVisualEffectView(effect: blurEffect)
blurView.frame = UIScreen.main.bounds
blurView.tag = 12345  // 用于后续查找和移除

2.2 模糊样式选择

样式 效果 适用场景
.light 浅色模糊 浅色主题 App
.dark 深色模糊 深色主题 App
.extraLight 更浅的模糊 需要更亮的遮罩
.regular 标准模糊 通用场景
.prominent 突出模糊 需要更强遮挡

secure_application 使用的是 .light 样式,在大多数场景下效果不错。

2.3 添加到 Window

// 获取当前 Window
if let window = UIApplication.shared.windows.first {
    window.addSubview(blurView)
}

添加到 Window 的最顶层,确保覆盖所有内容,包括 Flutter 的渲染视图。

2.4 移除模糊视图

if let window = UIApplication.shared.windows.first {
    window.viewWithTag(12345)?.removeFromSuperview()
}

通过 tag 找到之前添加的模糊视图并移除。

三、应用生命周期处理

3.1 Swift 端的生命周期监听

class SecureApplicationPlugin: NSObject, FlutterPlugin {
    var secured = false
    var channel: FlutterMethodChannel?

    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        switch call.method {
        case "secure":
            secured = true
            result(true)
        case "open":
            secured = false
            removeBlurView()
            result(true)
        case "lock":
            if secured { addBlurView() }
            result(true)
        case "unlock":
            removeBlurView()
            result(true)
        case "opacity":
            // 处理透明度参数
            result(true)
        default:
            result(FlutterMethodNotImplemented)
        }
    }
}

3.2 NotificationCenter 事件注册

NotificationCenter.default.addObserver(
    self,
    selector: #selector(applicationWillResignActive),
    name: UIApplication.willResignActiveNotification,
    object: nil
)

NotificationCenter.default.addObserver(
    self,
    selector: #selector(applicationDidBecomeActive),
    name: UIApplication.didBecomeActiveNotification,
    object: nil
)

3.3 事件处理

@objc func applicationWillResignActive() {
    if secured {
        addBlurView()
        channel?.invokeMethod("lock", arguments: nil)
    }
}

@objc func applicationDidBecomeActive() {
    // 延迟移除,等待 Flutter 渲染完成
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        self.removeBlurView()
    }
}

3.4 延迟移除的必要性

用户切回 App
    │
    ├── t=0ms:   iOS 调用 applicationDidBecomeActive
    ├── t=0ms:   Flutter 开始渲染(SecureGate 模糊遮罩还没显示)
    ├── t=100ms: Flutter 渲染完成,SecureGate 遮罩已显示
    ├── t=500ms: iOS 移除原生模糊视图
    └── 用户看到的始终是模糊画面 ✅

如果不延迟移除:

用户切回 App
    │
    ├── t=0ms:   iOS 立即移除原生模糊视图
    ├── t=0ms:   Flutter 还没渲染完成
    ├── t=0-100ms: 用户短暂看到未保护的内容 ❌
    └── t=100ms: Flutter SecureGate 遮罩才显示

📌 这就是 nativeRemoveDelay 参数的由来。Dart 层默认设置为 1000ms,iOS 原生端默认 500ms,取较大值来确保安全。

四、iOS 与 Android 的对比

4.1 保护机制对比

维度 Android iOS
截屏防护 ✅ 系统级(FLAG_SECURE) ❌ 无法阻止
录屏防护 ✅ 系统级 ❌ 无法阻止
应用切换器 自动隐藏 手动添加模糊视图
实现复杂度 低(一行代码) 中(需要管理视图生命周期)
延迟问题 需要延迟移除原生遮罩
用户体验 切换器显示空白 切换器显示模糊画面

4.2 代码量对比

平台 核心代码行数 主要工作
Android ~40行 FLAG_SECURE 开关
iOS ~100行 模糊视图创建/移除 + 生命周期管理
OpenHarmony ~234行 隐私模式 + 窗口事件 + 生命周期

4.3 OpenHarmony 的定位

OpenHarmony 的 setWindowPrivacyMode 在能力上更接近 Android 的 FLAG_SECURE:

能力 Android iOS OpenHarmony
系统级截屏防护
系统级录屏防护
应用切换器保护 自动 手动 自动
需要原生遮罩视图
需要延迟移除

💡 好消息:OpenHarmony 不需要像 iOS 那样创建原生模糊视图,也不需要处理延迟移除的问题。这简化了实现。

五、iOS 端的 opacity 处理

5.1 原生端的 opacity 应用

case "opacity":
    if let args = call.arguments as? [String: Any],
       let opacity = args["opacity"] as? Double {
        self.opacity = CGFloat(opacity)
        updateBlurViewOpacity()
    }
    result(true)

5.2 动态更新模糊视图透明度

func updateBlurViewOpacity() {
    if let window = UIApplication.shared.windows.first,
       let blurView = window.viewWithTag(12345) {
        blurView.alpha = CGFloat(opacity)
    }
}

iOS 端的 opacity 直接控制原生模糊视图的 alpha 值。而在 OpenHarmony 端,opacity 参数主要由 Flutter 层的 SecureGate 处理,原生端不需要做特殊处理。

六、从 iOS 实现中学到的经验

6.1 对 OpenHarmony 适配的启示

iOS 的做法 OpenHarmony 是否需要 原因
创建原生模糊视图 setWindowPrivacyMode 自动处理
延迟移除原生遮罩 没有原生遮罩需要移除
NotificationCenter 监听 ✅(用不同方式) 需要监听前后台切换
通知 Dart 层 lock 窗口失焦时通知锁定

6.2 需要注意的点

  1. 不要照搬 iOS 的模糊视图方案:OpenHarmony 有系统级保护,不需要
  2. 生命周期监听仍然需要:虽然方式不同,但目的相同
  3. nativeRemoveDelay 在 OpenHarmony 上可以更短:因为没有原生遮罩需要移除

6.3 三平台方案总结

Android:  FLAG_SECURE ──────────────────► 系统自动处理一切
iOS:      UIVisualEffectView ──────────► 手动遮挡 + 延迟移除
OHOS:     setWindowPrivacyMode ────────► 系统自动处理 + 事件监听

七、Web 和 Windows 端简述

7.1 Web 端

// secure_application_web.dart
class SecureApplicationWeb {
  // 监听 visibilitychange 事件
  // 页面不可见时通知 Dart 层锁定
  // 无法阻止截屏
}

Web 端能力最弱,只能检测页面可见性变化,无法阻止截屏或录屏。

7.2 Windows 端

// SecureApplicationPlugin.cpp
// 监听窗口最小化和锁屏事件
// 无法阻止截屏

Windows 端可以检测窗口最小化和系统锁屏,但同样无法阻止截屏。

7.3 五平台能力矩阵

能力 Android iOS OHOS Web Windows
截屏防护
录屏防护
切换器保护 N/A N/A
模糊遮罩
认证解锁

总结

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

  1. UIVisualEffectView:原生模糊视图遮挡应用内容
  2. 生命周期监听:willResignActive 添加遮罩,didBecomeActive 延迟移除
  3. 延迟移除:500ms 延迟确保 Flutter 渲染完成后再移除原生遮罩
  4. 能力限制:iOS 无法阻止截屏/录屏,只能遮挡
  5. 与 OpenHarmony 的差异:OHOS 有系统级保护,不需要原生遮罩

下一篇我们正式进入 OpenHarmony 适配——搭建 ohos 插件工程。

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


相关资源:

iOS 应用切换器效果
iOS 端应用切换器中的模糊遮罩效果

Logo

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

更多推荐