You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS18非场景化App防录屏问题:isCaptured弃用后sceneCaptureState失效

iOS 18 非场景化App防录屏解决方案

核心问题分析

iOS 18弃用了UIScreen.main.isCaptured和UIScreen.capturedDidChangeNotification,官方推荐的sceneCaptureState在非场景化架构下存在启动状态判断失效问题:先开启录屏再启动App、杀后台重启时,window.traitCollection.sceneCaptureState会错误返回false,仅状态变化监听registerForTraitChanges([UITraitSceneCaptureState.self])能正常工作。

可行解决方案

1. 状态监听+启动主动校验补全

利用registerForTraitChanges的可靠性,同时在App启动阶段主动强制刷新trait collection,获取真实录屏状态:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 初始化window并设为keyWindow
    window?.makeKeyAndVisible()
    
    // 强制刷新trait collection,获取正确的录屏状态
    window?.traitCollection.performAsCurrent { [weak self] in
        let captureState = UITraitCollection.current.sceneCaptureState
        self?.handleCaptureStateChange(to: captureState)
    }
    
    // 注册录屏状态变化监听
    window?.registerForTraitChanges([UITraitSceneCaptureState.self], with: self)
    
    return true
}

// 处理trait变化回调
func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    let captureState = window?.traitCollection.sceneCaptureState ?? .inactive
    handleCaptureStateChange(to: captureState)
}

// 统一处理录屏状态变更逻辑
private func handleCaptureStateChange(to state: UITraitSceneCaptureState) {
    if state == .active {
        // 执行防录屏逻辑:显示遮罩、暂停敏感内容展示等
    } else {
        // 恢复正常业务逻辑
    }
}

原理:performAsCurrent会将当前window的trait collection设为全局当前集合,此时获取的sceneCaptureState会同步系统真实录屏状态,解决启动时的判断误差。

2. 兜底方案:截图检测补充

如果上述方法在极端场景失效,可补充截图检测作为应急手段:

// 监听系统截图通知
NotificationCenter.default.addObserver(self, selector: #selector(handleScreenshotTriggered), name: UIApplication.userDidTakeScreenshotNotification, object: nil)

@objc private func handleScreenshotTriggered() {
    // 触发应急防录屏处理:临时隐藏敏感内容等
}

注意:该方法仅能检测截图,无法直接识别录屏,但可作为录屏检测的补充——录屏过程中的截图会触发此通知。

3. 多版本兼容适配

为兼容iOS 17及以下版本,需做版本分支处理:

if #available(iOS 18.0, *) {
    // 执行iOS 18专属逻辑
} else {
    // 沿用旧版UIScreen API
    let isCaptured = UIScreen.main.isCaptured
    handleCaptureStateChange(to: isCaptured ? .active : .inactive)
    NotificationCenter.default.addObserver(self, selector: #selector(legacyCaptureStateChanged), name: UIScreen.capturedDidChangeNotification, object: nil)
}

@objc private func legacyCaptureStateChanged() {
    let isCaptured = UIScreen.main.isCaptured
    handleCaptureStateChange(to: isCaptured ? .active : .inactive)
}

关键注意事项

  • 必须在window完成初始化并成为keyWindow后,再执行状态校验,否则traitCollection无法同步系统状态。
  • handleCaptureStateChange方法内避免执行耗时操作,防止阻塞UI线程。
  • 测试需覆盖全场景:先录屏再启动App、后台重启App、录屏中切换App、录屏停止等。

内容的提问来源于stack exchange,提问作者Shrief_Nasr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 23:34:59