【问题标题】:Firebase function to fetch data from Firebase DB to make Push notificationFirebase 函数从 Firebase DB 获取数据以进行推送通知
【发布时间】:2018-06-02 11:49:54
【问题描述】:

我有带有 Firebase 数据库和 Firebase 云消息传递的聊天应用程序。我可以通过控制台发送 firebase 通知,但在实际情况下它应该是自动的。为了自动通知,我的朋友为我写了Index.js(添加在云功能中)文件,但它不发送通知。

根据我们的逻辑函数,只要有任何新条目(在任何节点或任何房间),就应该触发,并通过 firebase 函数获取这些值并向 FCM 服务器发出发布请求以通知接收器设备(获取接收器的值设备从 token_To)。

  1. 留言
  2. Message_From
  3. 时间
  4. 类型
  5. token_To

Index.js

var functions = require('firebase-functions');
var admin = require('firebase-admin');


var serviceAccount = require('./demofcm-78aad-firebase-adminsdk-4v1ot-2764e7b580.json');
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://demofcm-78aad.firebaseio.com/"
})

// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
//  response.send("Hello from Firebase!");
// });
exports.setUserNode = functions.auth.user().onCreate(event => {
  // ...
});

exports.notifyMsg = functions.database.ref('/{chatroom}/{mid}/')
    .onWrite(event => {

       if (!event.data.val()) {
         return console.log('Message Deleted');
       }

       const getDeviceTokensPromise = admin.database().ref('/{chatroom}/{mid}/token_to').once('value');


       return Promise.all([getDeviceTokensPromise]).then(results => {
         const tokensSnapshot = results[0];

         if (!tokensSnapshot.hasChildren()) {
           return console.log('There are no notification tokens to send to.');
         }

         const payload = {
           notification: {
             title: 'You have a new Message!',
             body: event.data.val().Message
           }
         };

         const tokens = Object.keys(tokensSnapshot.val());

         return admin.messaging().sendToDevice(tokens, payload).then(response => {

           const tokensToRemove = [];
           response.results.forEach((result, index) => {
             const error = result.error;
             if (error) {
               console.error('Failure sending notification to', tokens[index], error);

               if (error.code === 'messaging/invalid-registration-token' ||
                   error.code === 'messaging/registration-token-not-registered') {
                 tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
               }
             }
           });
           return Promise.all(tokensToRemove);
         });
       });
});

Firebase 函数日志

如何从数据库中获取同一房间(9810012321-9810012347)或任何其他房间(9810012321-9810012325)中任何新添加节点的上述值并将其发送到 FCM 以进行通知

提前致谢。

【问题讨论】:

    标签: javascript android node.js firebase firebase-realtime-database


    【解决方案1】:

    我所做的是创建了一个消息节点,我相信这是通过用户密钥来完成的。即,具有接收者(toId)和发送者(fromId)键来发送通知。 希望对您有所帮助。

    exports.sendMessageNotification = functions.database.ref('/messages/{pushId}')
    .onWrite(event => {
        let message = event.data.current.val();
        console.log('Fetched message', event.data.current.val());
        let senderUid = message.fromId;
        let receiverUid = message.toId;
        let promises = [];
    
        console.log('message fromId', receiverUid);
        console.log('catch me', admin.database().ref(`/users/${receiverUid}`).once('value'));
    
        if (senderUid == receiverUid) {
            //if sender is receiver, don't send notification
            //promises.push(event.data.current.ref.remove());
            return Promise.all(promises);
        }
    
        let messageStats = message.messageStatus;
        console.log('message Status', messageStats);
    
        if (messageStats == "read") {
            return Promise.all(promises);
        }
    
        let getInstanceIdPromise = admin.database().ref(`/users/${receiverUid}/pushToken`).once('value');
        let getSenderUidPromise = admin.auth().getUser(senderUid);
    
        return Promise.all([getInstanceIdPromise, getSenderUidPromise]).then(results => {
            let instanceId = results[0].val();
            let sender = results[1];
            console.log('notifying ' + receiverUid + ' about ' + message.text + ' from ' + senderUid);
            console.log('Sender ', sender);
            var badgeCount = 1;
            let payload = {
                notification: {
                    uid: sender.uid,
                    title: 'New message from' + ' ' + sender.displayName,
                    body: message.text,
                    sound: 'default',
                    badge: badgeCount.toString()
                },
                'data': { 
                    'notificationType': "messaging", 
                    'uid': sender.uid
              }
            };
            badgeCount++;
            admin.messaging().sendToDevice(instanceId, payload)
                .then(function (response) {
                    console.log("Successfully sent message:", response);
                })
                .catch(function (error) {
                    console.log("Error sending message:", error);
                });
        });
    });
    

    【讨论】:

    • 它对你有用吗?做同样的事情我想要实现的目标
    • 如果应用上有 100 个用户,那么这将获取完整的消息节点。为了避免这种情况,我为 2 个用户创建了 1 个房间。这将只获取特定的房间消息
    • 这是因为每次写入消息节点都会触发发送到/users/${receiverUid}/pushToken的函数和通知。
    • 您正在使用按键获取固定节点(消息)。您的代码可能会取代我的代码,但我的问题是如何只获取我上面提到的新添加的数据,这些数据可以在任何房间内并且只能使用任何密钥。如果您对我的问题有任何想法,请帮助我。因为我的 Javascript 不太好
    【解决方案2】:
    const getDeviceTokensPromise = event.data.child('token_To');
    

    应该可以从数据库引用中获取数据。

    没有通配符的固定路径,如下所示

    const getDeviceTokensPromise = admin.database().ref('/${chatroom}/${mid}/token_to').once('value');
    

    其中 chatroom 和 mid 是包含值的变量

    第二件事:

    if (!tokensSnapshot.exists()) { 
    

    应该代替

    if (!tokensSnapshot.hasChildren()) {
    

    第三件事:

    我不确定推送通知 tokenId 但 需要做吗?

    const tokens = Object.keys(tokensSnapshot.val());

    也许我们可以像下面这样直接使用来发送推送通知

    const tokens = tokensSnapshot.val();

    【讨论】:

    • 如何获得可变聊天室因为它是独一无二的。声明为固定聊天室不适用于所有聊天室
    • 你试过第一行吗?我想我可以解决你的问题
    • 我试过了,但它不起作用。我想我需要点击属于聊天用户的正确聊天室
    • 我的错,实际上上面一行不需要.val,我已经更新了答案,请检查它
    • 它仍然不会根据房间名称从数据库中获取新输入的节点,因为我们无法手动声明房间名称。我们需要获取节点新进入数据库的任何位置
    【解决方案3】:

    您可以将所有设备令牌存储在一个名为令牌的节点中,如我的示例中所示。如果您希望一个用户能够在多个设备上获取通知,则令牌可以是一个数组。无论如何,按它们的 UID 存储它们。

    这适用于 Android 和 iOS。

    这是我的代码:

    function loadUsers() {
       let dbRef = admin.database().ref('/tokens/'  +  recieveId);
       console.log(recieveId)
       let defer = new Promise((resolve, reject) => {
           dbRef.once('value', (snap) => {
               let data = snap.val();
    
               console.log("token: " + data.token)
               //userToken = data.token
               resolve(data.token);
            }, (err) => {
               reject(err);
            });
        });
        return defer;
    }
    

    接下来我们创建通知。我创建了一个 lastMessage 节点来捕获聊天中发送的最后一条消息。每次在两个用户之间的聊天中发送新消息时,它都会更新。使获得价值变得容易。还可以轻松地在“对话”屏幕上显示消息,其中包含与当前用户进行对话的用户列表。

    exports.newMessagePush = 
    functions.database.ref('/lastMessages/{rcId}/{sendId}').onWrite(event => {
    
    if (!event.data.exists()) {
        console.log("deleted message")
        return;
    }
    recieveId = event.params.rcId
    
    //let path = event.data.adminRef.toString();
    // let recieveId = path.slice(53, 81);
    
    return loadUsers().then(user => {
        console.log("Event " + event.data.child("text").val());
    
        let payload = {
            notification: {
                title:  event.data.child("name").val(),
                body:  event.data.child("text").val(),
                sound: 'default',
                priority: "10",
    
                }
            };
    
            return admin.messaging().sendToDevice(user , payload);
        });     
    });
    

    要在您当前的数据结构上实现此逻辑,只需更改此行:

        let dbRef = admin.database().ref('/tokens/'  +  recieveId);
    

    还有这一行:

        exports.newMessagePush = 
    
      functions.database.ref('/lastMessages/{rcId}/{sendId}').onWrite(event 
        => {
    

    到您的令牌位置:

        let dbRef = 
        admin.database().ref('/${chatroom}/${mid}/token_to');
    

    以及您的对话地点:

         exports.notifyMsg = functions.database.ref('/{chatroom}/{mid}/')
         .onWrite(event => {
    

    然后只需将通知负载更改为您要显示的消息,并在 sendToDevice 函数的末尾抛出错误处理,就像您在代码中所做的那样。

    希望您已经弄清楚了所有这些,但如果没有,这可能会帮助您或其他尝试使用 Cloud Functions 进行通知的人。

    【讨论】:

    • 谢谢。我会尽快检查并回复您。
    • 我在 SO 和 git hub bt 上尝试了很多这个和随机的其他解决方案,但仍然没有解决方案
    【解决方案4】:
     let payload = {
            notification: {
                uid: sender.uid,
                title: 'New message from' + ' ' + sender.displayName,
                body: message.text,
                sound: 'default',
                badge: badgeCount.toString()
            },
            'data': { 
                'notificationType': "messaging", 
                'uid': sender.uid
          }
        };
    

    有两种类型的 FCM。 1) 数据 2) 通知

    详细概述:FCM Reference

    您必须修复两个 FCMS 的有效负载。对于数据 FCM,您必须在 FCM 服务(客户端)中提取数据并根据需要生成推送通知。

    【讨论】:

    • 发出通知并不难,但从被触发的特定房间从数据库获取数据有点复杂
    • 谢谢,但我已经阅读了 firebase 文档,但我的意思是,每当新数据插入房间时,我都无法获取子节点。请再次阅读我的问题。如果有任何困惑,请告诉我
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 2020-01-04
    • 2016-10-15
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 2017-03-05
    相关资源
    最近更新 更多