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

SwiftUI Firebase认证:断网后保持用户登录状态问题求助

解决方案

1. 修复auth.setPersistence(.local)无法识别的问题

确保你的Firebase Auth依赖为最新版本,然后在登录/注册操作之前正确设置持久化:

  • 在logIn和signUp方法中,先调用同步的setPersistence方法(需包裹在错误处理逻辑中):
func logIn(email: String, password: String) async throws {
    mail = email
    // 设置本地持久化(必须在登录前调用)
    try Auth.auth().setPersistence(.local)
    let authRes = try await Auth.auth().signIn(withEmail: email, password: password)
}

func signUp(email: String, password: String) async throws {
    mail = email
    try Auth.auth().setPersistence(.local)
    let authRes = try await Auth.auth().createUser(withEmail: email, password: password)
}

注:setPersistence是Firebase Auth的同步方法,需在登录/注册请求执行前调用,确保会话被持久化到本地。

2. 解决断网自动登出问题:监听Auth状态变化

不要依赖手动维护的loggedIn变量判断登录状态,改用Firebase的AuthStateDidChangeListener自动同步状态,即使断网也能保留本地持久化的用户信息:
在AppViewModel的初始化方法中添加监听:

class AppViewModel: ObservableObject {
    @Published var loggedIn = false
    private var authStateListener: AuthStateDidChangeListenerHandle?
    
    init() {
        // 初始化时先从本地读取状态
        loggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn")
        
        // 添加Auth状态监听
        authStateListener = Auth.auth().addStateDidChangeListener { [weak self] auth, user in
            guard let self = self else { return }
            let isLoggedIn = user != nil
            self.loggedIn = isLoggedIn
            // 同步保存到UserDefaults
            UserDefaults.standard.set(isLoggedIn, forKey: "isLoggedIn")
        }
    }
    
    // ViewModel销毁时移除监听
    deinit {
        if let listener = authStateListener {
            Auth.auth().removeStateDidChangeListener(listener)
        }
    }
    
    // ...其他已有方法
}

这样即使网络断开,Firebase会保留本地持久化的用户会话,loggedIn会保持true,不会自动登出。

3. 修复ContentView的状态判断逻辑

移除ContentView中onAppear的手动赋值,让监听自动同步状态:

struct ContentView: View {
    @EnvironmentObject var viewModel: AppViewModel
    
    var body: some View {
        NavigationView{
            if viewModel.loggedIn{
                HomeView()
            } else {
                LoginView()
            }
        }
        // 移除原onAppear中的手动赋值代码
    }
}

4. 实现断网提示功能

用NWPathMonitor监听网络状态,在断网时弹出提示:
在AppViewModel中添加网络监听:

import Network

class AppViewModel: ObservableObject {
    @Published var showNetworkAlert = false
    private let networkMonitor = NWPathMonitor()
    
    init() {
        // ...之前的Auth监听代码
        
        // 网络状态监听
        networkMonitor.pathUpdateHandler = { path in
            DispatchQueue.main.async {
                let isConnected = path.status == .satisfied
                if !isConnected && self.loggedIn {
                    self.showNetworkAlert = true
                }
            }
        }
        let queue = DispatchQueue(label: "NetworkMonitor")
        networkMonitor.start(queue: queue)
    }
    
    // ...其他已有方法
}

然后在ContentView中添加Alert:

struct ContentView: View {
    @EnvironmentObject var viewModel: AppViewModel
    
    var body: some View {
        NavigationView{
            // ...原视图代码
        }
        .alert(isPresented: $viewModel.showNetworkAlert) {
            Alert(
                title: Text("网络断开"),
                message: Text("当前网络不可用,请检查连接后重试"),
                dismissButton: .default(Text("知道了"))
            )
        }
    }
}

5. 关于UserDefaults不生效的问题

之前手动保存loggedIn不生效,是因为没有和Auth的实际状态同步。现在通过Auth状态监听自动更新UserDefaults,同时初始化时从UserDefaults读取初始值,就能保证状态的一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 17:16:29