iOS应用启动时如何检查Firebase手机认证用户的登录状态?
Firebase手机号验证重启后登录状态未同步到UI的问题修复
问题根源
- 实例不统一:你在
AppDelegate中创建了临时的UserManagerModel()实例并调用appLaunch_listener,但这个实例和UI层通过@EnvironmentObject依赖的实例是完全独立的两个对象。监听回调中修改的loggedIn变量只作用于临时实例,无法同步到UI使用的实例,导致UI无法感知登录状态变化。 - 线程问题:
Auth.auth().addStateDidChangeListener的回调可能在后台线程执行,直接修改@Published变量可能无法正确触发UI更新。
修复步骤
1. 全局统一UserManagerModel实例
在App级别初始化唯一的UserManagerModel实例,并注入到SwiftUI环境中,确保所有UI组件共享同一个实例:
class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? // 声明全局唯一的用户管理实例 let userManager = UserManagerModel() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { FirebaseApp.configure() // 调用全局实例的监听方法 userManager.appLaunch_listener() // 配置根视图并注入环境对象 let contentView = LaunchView().environmentObject(userManager) window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = UIHostingController(rootView: contentView) window?.makeKeyAndVisible() return true } }
2. 确保@Published变量在主线程更新
修改UserManagerModel的appLaunch_listener方法,将loggedIn的修改强制放在主线程执行:
func appLaunch_listener() { Auth.auth().addStateDidChangeListener({ auth, user in DispatchQueue.main.async { if user != nil { print("user is logged in") self.loggedIn = true print(self.loggedIn) } else { print("user is not logged in") self.loggedIn = false } } }) }
3. 优化登录验证后的状态同步(可选)
在verifyCode方法中,登录成功后主动设置loggedIn为true,确保UI及时响应:
func verifyCode(code: String, completion: @escaping (Error?) -> Void) { let verificationId = UserDefaults.standard.string(forKey: Constants.verificationIdStorageKey) ?? "" let credential = PhoneAuthProvider.provider().credential(withVerificationID: verificationId, verificationCode: code) Auth.auth().signIn(with: credential) { authResult, error in DispatchQueue.main.async { if error == nil { self.userInfo() self.loggedIn = true // 登录成功后主动更新状态 } completion(error) } } }
4. 优化LaunchView初始加载体验(可选)
由于Firebase状态监听是异步的,应用启动时loggedIn初始为false,可能会短暂显示登录界面。可以添加加载状态优化:
struct LaunchView: View { @EnvironmentObject var userManager : UserManagerModel @State private var isLoading = true var body: some View { Group { if isLoading { ProgressView("加载中...") } else if userManager.loggedIn { HomeView() .onAppear{ userManager.userInfo() } } else { userManager.newUser ? OnboardingView() : LoginForm() } } .onAppear { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { isLoading = false } } } }
关键说明
- 必须保证整个应用中只使用同一个
UserManagerModel实例,环境对象的核心作用就是共享单一实例。 @Published变量的修改必须在主线程执行,否则无法触发SwiftUI的UI更新机制。- Firebase的
addStateDidChangeListener会在应用启动时自动触发一次回调,无需额外手动检查用户状态。
内容的提问来源于stack exchange,提问作者appdevmejia
相关产品推荐
相关产品推荐

