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
相关产品推荐
相关产品推荐

