在Firebase中处理用户在线和离线状态

4
我希望在我的Web应用程序中处理在线和离线状态,以便用户可以看到谁在线,谁不在线。
我发现了这个很好的教程,它解释得非常好,但我卡住了。
链接:https://blog.campvanilla.com/firebase-firestore-guide-how-to-user-presence-online-offline-basics-66dc27f67802 我认为 cloud-functions 存在问题,因为我在那里遇到了一个错误。
此外,该教程是2017年12月发布的,我知道 cloud-functions 已经更新了,但我不知道如何更新代码。
文档链接:https://firebase.google.com/docs/functions/beta-v1-diff 有人能否查看一下这个教程,并帮我解决问题吗?
云函数:
 const functions = require('firebase-functions');
 const Firestore = require('@google-cloud/firestore');
 const firestore = new Firestore();

 exports.onUserStatusChanged = functions.database
  .ref('/status/{userId}') // Reference to the Firebase RealTime database key
  .onUpdate((event, context) => {

    const usersRef = firestore.collection('/users'); // Create a reference to 
    the Firestore Collection

    return event.before.ref.once('value')
      .then(statusSnapshot => snapShot.val()) // Get latest value from  the Firebase Realtime database
      .then(status => {
        // check if the value is 'offline'
        if (status === 'offline') {
          // Set the Firestore's document's online value to false
          usersRef
            .doc(event.params.userId)
            .set({
              online: false
            }, {
              merge: true
            });
        }
        return
      })
  });
3个回答

7

有人有使用 Firebase 9 的示例吗? - peter

6
我将发布完全可用的代码,以帮助像我一样遇到困难的人。
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

const firestore = functions.firestore;

exports.onUserStatusChange = functions.database
    .ref('/status/{userId}')
    .onUpdate((event, context) => {

        var db = admin.firestore();
        var fieldValue = require("firebase-admin").firestore.FieldValue;

        const usersRef = db.collection("users");
        var snapShot = event.after;

        return event.after.ref.once('value')
            .then(statusSnap => snapShot.val())
            .then(status => {
                if (status === 'offline'){
                    usersRef
                        .doc(context.params.userId)
                        .set({
                            online: false
                        }, {merge: true});

                }
                return null;
            })
});

有了你的代码,我终于可以部署了,但是它不起作用... status === 'offline' 是指 Firebase 离线,而不是 Firestore 吗? - FilipeOS
是的,它将获取Firebase状态,然后将其传递给Firestore。 - Danial
我认为我的问题是我没有在我的Flutter应用程序中持续检查用户状态...需要看一个好的教程。 - FilipeOS
@Danial 我的朋友,你的答案还有效吗?还是需要更新? - Mohammed Hamdan

1
要知道用户的在线状态,我们只需要一个事件。Firebase Functions不是免费的,还需要部署等操作。因此,为了触发事件,我们可以使用Firebase Cloud Messaging怎么样?它是免费且无限制的。即使通知关闭,我们也可以处理消息事件。接下来是我在React Native上的实现方式。
//应用程序通用代码:
import auth  from '@react-native-firebase/auth';
import database from '@react-native-firebase/database';
import messaging from '@react-native-firebase/messaging';


async requestUserPermission() {
    const authStatus = await messaging().requestPermission();
    const enabled = 
      authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
      authStatus === messaging.AuthorizationStatus.PROVISIONAL;
      
    if (enabled) {
        console.log('Authorization status:', authStatus);
    }
}

updateFCMToken() {
    if (!messaging().isDeviceRegisteredForRemoteMessages)
    messaging().registerDeviceForRemoteMessages()
        .then((value) => {
            messaging().getToken().then( async (fcmToken) => {
            // Update backend (e.g. Firestore) with our token for the user
            });
    });
}

componentDidMount(){
    requestUserPermission();
    updateFCMToken();
    
    //-*-Update Online/Offline in REALTIMEDATABASE-*-*-*-*
    if (auth().currentUser) {
        var userStatusDatabaseRef = database().ref('/users/' + auth().currentUser.uid);
        var isOfflineForDatabase = {
            status: 'offline',
            last_changed: database.ServerValue.TIMESTAMP,
        };
        var isOnlineForDatabase = {
            status: 'online',
            last_changed: database.ServerValue.TIMESTAMP,
        };
        database().ref('.info/connected').on('value', 
        function (snapshot) {
            userStatusDatabaseRef.onDisconnect().set(
                isOfflineForDatabase).then(
                    function () {
                        userStatusDatabaseRef.set(isOnlineForDatabase);
                });
        });
    }
    
    //-*-Register Handle Message-*-*-*-*
    //-*-Here you get uid of user with online/offline status which you triggered using admin apis
    this.unsubscribeMessage = messaging().onMessage(remoteMessage => {
        Alert.alert(re moteMessage.notification.title, 
        remoteMessage.notification.body);
    });
}

//ADMIN APP CODE WHICH IS A SIMPLE NODEJS SERVER:

    //-*-In below code admin app listens when user is online/offline
    var userStatusOnlineRef =  database().ref('/users').orderByChild('status').equalTo('online');
    userStatusOnlineRef.on('value', (snapshot) => {
        //-*-Get the uid and use it to send to relevant users-*-
    });

    var userStatusOnlineRef =  database().ref('/users').orderByChild('status').equalTo('offline');
    userStatusOnlineRef.on('value', (snapshot) => {
        //-*-Get the uid and use it to send to relevant users-*-
    });

FINALLY TRIGGER MULTICAST MESSAGE TO APPLICABLE USERS:

var admin = require('firebase-admin');
const serviceAccount = require("./serviceAvccount.json");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://***.firebaseio.com"
});

const registrationTokens = [
    '....',
    '....',
];

const message = {
    //-*-Pass uid and online/offline status
    notification: { title: '', body: '', element: '', element: '' },
    tokens: registrationTokens,
};

admin.messaging().sendMulticast(message)
    .then((response) => {
        if (response.successCount > 0)
        console.log(response.successCount + ' messages were sent successfully');

        if (response.failureCount > 0) {
            const failedTokens = [];
            response.responses.forEach((resp, idx) => {
                if (!resp.success) {
                    failedTokens.push(registrationTokens[idx]);
                }
            });
            console.log('List of tokens that caused failures: ' + failedTokens);
        }
    })
    .catch((error) => {
        console.log('Error sending message:', error);
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接