Search code examples
iosfirebasefirebase-realtime-databasefirebase-authentication

iOS Firebase Swift, using on OnDisconnect to monitor online status does not work


I would like to monitor the online status of users in Firebase (i.e., to keep a log of who exactly is online), and of course I would like to this online status to react/update as soon as a user logs out or gets disconnected.

I am using this code towards the end of my ViewDidLoad and this seems to work fine for printing online/offline exactly when desired (i.e., connection is lost or user logs out, both of which I tested).

FIRAuth.auth()?.addStateDidChangeListener() { auth, user in
if user != nil {
   print("ONLINE")
   databaseRef.child("users").child((FIRAuth.auth()?.currentUser?.uid)!).child("OnlineStatus").setValue("ON")
 } else { 
   print("OFFLINE")
 }
}

Of course, where this prints 'offline', it is too late to change the entry of OnlineStatus since the connection has already been lost. To correct for this, I put this additional line below the above:

databaseRef.child("users").child((FIRAuth.auth()?.currentUser?.uid)!).child("OnlineStatus").onDisconnectSetValue("OFF")

My understanding was that this would do specifically what I desire, namely change the desired value to 'OFF' as soon as the connection is lost/disrupted. But this OnDisconnect seems to have no effect whatsoever, and I am confused what I am misunderstanding?


Following Jay's answer, I am now using this code (which is taken from Firebase documentation), but it still won't work. Any ideas?

let myConnectionsRef = databaseRef.child("users").child((FIRAuth.auth()?.currentUser?.uid)!).child("OnlineStatus")
    
let connectedRef = FIRDatabase.database().reference(withPath: ".info/connected")
    
    connectedRef.observe(.value, with: { snapshot in
        
        guard let connected = snapshot.value as? Bool, connected else {
            return
        }
    
        let con = myConnectionsRef
        con.setValue("YES")
        
        // when this device disconnects, remove it
        // con.onDisconnectRemoveValue()
        con.onDisconnectSetValue("OFF")
        
    })

Solution

  • OnDisconnect tells the server to take an action when the client disconnects. One use case would be an online chat system

    Users can see other users, select them and have a chat. Imagine a structure

    connected_status
      uid_0: true
      uid_1: true
      uid_2: false
    

    All clients observe the connected_status node and when a users status changes, their UI is updated - in this case uid_2 has disconnected so their node is set to false. This is done by

    child("connected_status).child(myUid).onDisconnectSetValue(false)
    

    This function is independent of you app knowing if it's connected or not - it a function just for the server.

    To monitor your apps connected status, observe a special node in Firebase

    ".info/connected"
    

    observing this node will let your App know when it's connected status changes.

    We use it in a KVO fashion in that when then the .info/connected changes, we update an 'isConnected' singleton app variable.

    In many of our views, we have a class ConnectedImage which is an image that's green when connected and red when disconnected. That class KVO's the singleton isConnected variable and updates it's color whenever it's status changes from false to true, true to false. This lets the user know when the are connected or not.

    For completeness, check out the Firebase documentation Offline Capabilities and scroll down the Detecting Connection State area.