开发iOS App:如何在任务切换器中显示锁屏并正确恢复?
嘿,我刚好踩过这个坑!你遇到的问题应该是因为在applicationDidEnterBackground里直接呈现锁屏VC的时机不对——系统在这个阶段对UI操作限制很多,而且任务切换器的快照是在这个方法执行前后生成的,所以大概率快照里还是会露出App的内容。给你几个经过验证的解决思路:
任务切换器的快照是App进入后台瞬间生成的,所以第一步要立刻用一个和锁屏风格一致的视图覆盖整个窗口,确保快照里没有敏感内容:
func applicationDidEnterBackground(_ application: UIApplication) { // 创建全屏覆盖视图,用和你的锁屏一致的背景色/样式 let snapshotOverlay = UIView(frame: UIScreen.main.bounds) snapshotOverlay.backgroundColor = .black // 或者你的锁屏背景色 snapshotOverlay.tag = 1000 // 标记方便后续移除 window?.addSubview(snapshotOverlay) // 不要在这里直接present锁屏VC,系统后台状态下不支持 }
然后监听UIApplicationProtectedDataDidBecomeAvailable通知——这个通知会在用户解锁设备、App可以访问受保护数据时触发,此时再移除覆盖并呈现锁屏:
// 在AppDelegate初始化时注册通知 override init() { super.init() NotificationCenter.default.addObserver( self, selector: #selector(showLockScreenWhenProtectedDataAvailable), name: UIApplication.protectedDataDidBecomeAvailableNotification, object: nil ) } @objc private func showLockScreenWhenProtectedDataAvailable() { // 先移除快照覆盖 window?.viewWithTag(1000)?.removeFromSuperview() // 全屏呈现锁屏VC let lockVC = LockViewController() lockVC.modalPresentationStyle = .fullScreen window?.rootViewController?.present(lockVC, animated: false) }
如果你适配了多场景,用SceneDelegate的方法比AppDelegate更可靠:
- 在
sceneDidEnterBackground(_ scene: UIScene)里添加快照覆盖,逻辑和上面一致; - 在
sceneWillEnterForeground(_ scene: UIScene)里不要急着移除覆盖,等用户完成解锁验证后再移除并恢复正常内容。
一定要把锁屏VC的modalPresentationStyle设为.fullScreen,如果用默认的.automatic或者其他样式,可能会在呈现瞬间露出下方的App内容,完全失去锁屏的意义。
如果App在后台被系统杀掉,重启时要直接进入锁屏状态:在application(_:didFinishLaunchingWithOptions:)或者场景代理的scene(_:willConnectTo:options:)里,判断用户是否尚未完成本次会话的解锁验证,如果是,直接呈现锁屏VC。
最后提醒一下:绝对不要在applicationDidEnterBackground里直接present VC,系统在后台状态下对模态呈现的支持非常有限,容易出现无响应、快照异常甚至Crash的问题。
内容的提问来源于stack exchange,提问作者Marco D.

