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

Firebase Swift中如何检测用户在线/离线状态?求解决方案

Firebase Swift 实现用户在线/离线状态检测

核心问题修正

你当前代码存在几个关键问题:

  • 规则混淆:你配置的是Firestore的安全规则,但代码中使用的是Firebase Realtime Database,两者规则不通用,需要修改为Realtime Database的规则。
  • onDisconnect冲突:同时调用onDisconnectSetValue和onDisconnectRemoveValue会导致操作冲突,同一节点只能绑定一个onDisconnect操作。
  • 后台状态处理不全:applicationWillTerminate在iOS中不一定会被触发(比如应用被系统强杀),需要补充后台状态监听。

完整实现方案

1. 配置Realtime Database安全规则

替换你当前的Firestore规则,在Firebase控制台的Realtime Database页面设置规则:

{
  "rules": {
    "presence": {
      "$uid": {
        ".read": true,
        ".write": "$uid === auth.uid"
      }
    },
    ".info/connected": {
      ".read": true
    }
  }
}

这个规则确保用户只能修改自己的在线状态,同时允许读取连接状态和所有用户的在线状态。

2. 封装在线状态管理Service

优化你的OnlineOfflineService,确保操作Realtime Database的逻辑统一:

import Firebase

class OnlineOfflineService {
    static let shared = OnlineOfflineService()
    private let presenceRef = Database.database().reference(withPath: "presence")
    
    private init() {}
    
    // 更新用户在线状态
    func updateOnlineStatus(for uid: String, isOnline: Bool) {
        let userPresenceRef = presenceRef.child(uid)
        let statusData: [String: Any] = [
            "isOnline": isOnline,
            "lastUpdated": ServerValue.timestamp()
        ]
        userPresenceRef.setValue(statusData)
    }
    
    // 设置断开连接时的离线状态
    func setupDisconnectHandler(for uid: String) {
        let userPresenceRef = presenceRef.child(uid)
        // 断开连接时自动设置为离线
        userPresenceRef.onDisconnectUpdateChildValues([
            "isOnline": false,
            "lastUpdated": ServerValue.timestamp()
        ]) { error, ref in
            if let error = error {
                print("绑定断开连接事件失败: \(error.localizedDescription)")
            }
        }
    }
    
    // 监听指定用户的在线状态
    func observeUserStatus(for uid: String, completion: @escaping (Bool) -> Void) -> DatabaseHandle {
        return presenceRef.child(uid).child("isOnline").observe(.value) { snapshot in
            let isOnline = snapshot.value as? Bool ?? false
            completion(isOnline)
        }
    }
}

3. 在AppDelegate中处理连接状态和应用生命周期

import UIKit
import Firebase

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        
        // 启用本地持久化
        Database.database().isPersistenceEnabled = true
        
        // 监听连接状态
        let connectedRef = Database.database().reference(withPath: ".info/connected")
        connectedRef.observe(.value) { [weak self] snapshot in
            guard let isConnected = snapshot.value as? Bool, isConnected, let uid = Auth.auth().currentUser?.uid else {
                // 未连接或未登录,这里不主动设置离线,交给onDisconnect处理
                return
            }
            // 连接成功时设置在线状态,并绑定断开事件
            OnlineOfflineService.shared.updateOnlineStatus(for: uid, isOnline: true)
            OnlineOfflineService.shared.setupDisconnectHandler(for: uid)
        }
        
        return true
    }

    // 应用进入后台时,尝试设置离线状态(补充onDisconnect的场景)
    func applicationDidEnterBackground(_ application: UIApplication) {
        guard let uid = Auth.auth().currentUser?.uid else { return }
        OnlineOfflineService.shared.updateOnlineStatus(for: uid, isOnline: false)
    }

    // 应用回到前台时,重新设置在线状态
    func applicationDidBecomeActive(_ application: UIApplication) {
        guard let uid = Auth.auth().currentUser?.uid else { return }
        OnlineOfflineService.shared.updateOnlineStatus(for: uid, isOnline: true)
        OnlineOfflineService.shared.setupDisconnectHandler(for: uid)
    }
}

4. 关键逻辑说明

  • .info/connected监听:Realtime Database提供的特殊节点,实时返回当前客户端的连接状态(true/false)。
  • onDisconnectUpdateChildValues:这个操作会在客户端与服务器断开连接时自动执行,即使应用被强杀或设备断电,服务器也会触发该操作,确保状态准确。
  • 应用生命周期处理:进入后台时主动设置离线,回到前台时重新设置在线并绑定断开事件,覆盖onDisconnect无法处理的主动后台场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:01:21