SwiftUI:APP回到前台时在任意视图上层展示验证视图
解决SwiftUI中APP回到前台统一展示验证视图的问题
方案一:全局状态+自定义ViewModifier(纯SwiftUI方式)
通过全局状态管理验证视图的显示状态,搭配自定义ViewModifier实现全局监听,避免重复写监听代码。
- 全局状态管理类
import SwiftUI class AppAuthenticationManager: ObservableObject { static let shared = AppAuthenticationManager() @Published var shouldShowAuthView = false private init() { // 监听进入后台,标记需要验证 NotificationCenter.default.addObserver(self, selector: #selector(appEnteredBackground), name: UIApplication.didEnterBackgroundNotification, object: nil) // 监听回到前台,触发验证视图 NotificationCenter.default.addObserver(self, selector: #selector(appEnteredForeground), name: UIApplication.willEnterForegroundNotification, object: nil) } @objc private func appEnteredBackground() { shouldShowAuthView = true } @objc private func appEnteredForeground() { if shouldShowAuthView { DispatchQueue.main.async { self.shouldShowAuthView = true } } } // 验证完成后调用,重置状态 func completeAuthentication() { shouldShowAuthView = false } }
- 自定义ViewModifier
struct AuthenticationViewModifier: ViewModifier { @ObservedObject var authManager = AppAuthenticationManager.shared func body(content: Content) -> some View { content .fullScreenCover(isPresented: $authManager.shouldShowAuthView) { FullCoverViewDidEnterBg() .onDisappear { authManager.completeAuthentication() } } } } // 给View扩展,方便调用 extension View { func addAuthenticationCover() -> some View { self.modifier(AuthenticationViewModifier()) } }
- 应用到视图中
@main struct NavApp: App { var body: some Scene { WindowGroup { ContentView() .addAuthenticationCover() } } } struct ContentView: View { @State var isPresenting = true var body: some View { NavigationStack { VStack { Button("Present Full Cover") { isPresenting.toggle() } Text("Hello, world!") } .fullScreenCover(isPresented: $isPresenting) { FullCoverView() .addAuthenticationCover() // 子全屏视图也要添加 } } } } struct FullCoverView: View { @Environment(\.dismiss) var dismiss var body: some View { VStack { Text("FullCoverView") Button("dismiss") { dismiss() } } } } struct FullCoverViewDidEnterBg: View { @Environment(\.dismiss) var dismiss var body: some View { VStack { Text("请验证身份(面容ID/密码)") Button("验证完成") { dismiss() } } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.white) } }
方案二:借助UIKit获取顶层视图控制器(混合方式)
直接通过UIKit获取当前顶层视图控制器,强制弹出验证视图,无需修改现有SwiftUI视图结构。
- 扩展UIApplication获取顶层VC
import UIKit extension UIApplication { func topViewController() -> UIViewController? { let keyWindow = connectedScenes .filter({$0.activationState == .foregroundActive}) .map({$0 as? UIWindowScene}) .compactMap({$0}) .first?.windows .filter({$0.isKeyWindow}).first var topVC = keyWindow?.rootViewController while let presentedVC = topVC?.presentedViewController { topVC = presentedVC } return topVC } }
- 修改全局状态类,用UIKit弹出视图
class AppAuthenticationManager: ObservableObject { static let shared = AppAuthenticationManager() private init() { NotificationCenter.default.addObserver(self, selector: #selector(appEnteredForeground), name: UIApplication.willEnterForegroundNotification, object: nil) } @objc private func appEnteredForeground() { guard let topVC = UIApplication.shared.topViewController() else { return } // 将SwiftUI视图包装成UIHostingController let authView = FullCoverViewDidEnterBg() let hostingVC = UIHostingController(rootView: authView) hostingVC.modalPresentationStyle = .fullScreen topVC.present(hostingVC, animated: true) } }
- 初始化管理器
@main struct NavApp: App { let authManager = AppAuthenticationManager.shared var body: some Scene { WindowGroup { ContentView() } } }
方案对比
- 纯SwiftUI方案:符合SwiftUI状态驱动理念,代码易维护,但需要给每个弹出的全屏视图添加Modifier。
- 混合UIKit方案:无需修改现有视图结构,全局强制弹出验证视图,适合已有较多页面的项目,但需要处理SwiftUI与UIKit的视图转换。
内容的提问来源于stack exchange,提问作者SomeCoder
相关产品推荐
相关产品推荐

