简体   繁体   English

Firebase功能用于从Firebase DB获取数据以进行推送通知

[英]Firebase function to fetch data from Firebase DB to make Push notification

I have chat app with firebase database and Firebase cloud messaging. 我与firebase数据库和Firebase云消息传递聊天应用程序。 I can send firebase notification via console but in real scenario it should be automatic. 我可以通过控制台发送firebase通知,但在实际情况下它应该是自动的。 To make automatic notification,My friend wrote Index.js (Added in cloud functions) file for me but its not sending notifications. 为了自动通知,我的朋友为我写了Index.js(在云函数中添加)文件,但它没有发送通知。

As per our logic function should trigger whenever there is any new entries (in any node or in any room) and fetch these values by firebase function and make post request to FCM server to make notification to receiver device (get value of receiver device from token_To). 根据我们的逻辑函数,只要有任何新条目(在任何节点或任何房间)都应该触发,并通过firebase函数获取这些值,并向FCM服务器发出post请求以通知接收方设备(从token_To获取接收方设备的值) )。

  1. Message 信息
  2. Message_From Message_From
  3. Time 时间
  4. Type 类型
  5. token_To token_To

Firebase数据库结构

Index.js 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 function Log Firebase功能日志

Firebase云功能日志

How can i fetch above mentioned values of any newly added node in same room(9810012321-9810012347) or any other room(9810012321-9810012325) from database and send it to FCM to make notification 如何从数据库中获取同一房间(9810012321-9810012347)或任何其他房间(9810012321-9810012325)中任何新添加节点的上述值,并将其发送给FCM进行通知

Thanks in Advance. 提前致谢。

What i did is created a Message node and I believe doing this by users key. 我所做的是创建一个Message节点,我相信用户密钥就是这样做的。 ie, having the receiver(toId) and sender (fromId) key to send the notification. 即,使接收者(toId)和发送者(fromId)密钥发送通知。 Hope it helps. 希望能帮助到你。

Firebase消息节点

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);
            });
    });
});
const getDeviceTokensPromise = event.data.child('token_To');

should be there instated of getting data from database reference. 应该在那里从数据库引用中获取数据。

or 要么

with fixed path without wildcard like below 固定路径没有通配符,如下所示

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

where chatroom and mid is variable which contain value 聊天室和中间变量包含值

Second thing: 第二件事:

if (!tokensSnapshot.exists()) { 

should in replace of 应该取代

if (!tokensSnapshot.hasChildren()) {

third thing: 第三件事:

I am not sure about push notification tokenId but is it required to do? 我不确定推送通知tokenId但它是否需要这样做?

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

may be we can use directly like below to send push notification 也许我们可以像下面这样直接使用发送推送通知

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

 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
      }
    };

There are two types of FCMs. 有两种类型的FCM。 1) Data 2) Notification 1)数据2)通知

For detailed overview : FCM Reference 详细概述: FCM参考

You have to fix your payload for both FCMS. 您必须为两个FCMS修复有效负载。 And for Data FCM you have to extract Data in your FCM Service (Client) and generate a push notification according to your need. 对于Data FCM,您必须在FCM服务(客户端)中提取数据,并根据需要生成推送通知。

You could store all device tokens in a node called tokens like in my example. 您可以将所有设备令牌存储在名为令牌的节点中,如我的示例所示。 Tokens could be an array if you would like one user to be able to get notifications on multiple devices. 如果您希望一个用户能够在多个设备上获得通知,则标记可以是一个数组。 Anyway, store them by their UID. 无论如何,用他们的UID存储它们。

This works for both Andriod and iOS. 这适用于Andriod和iOS。

Here is my code: 这是我的代码:

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;
}

Next we create the notification. 接下来我们创建通知。 I created a lastMessage node to capture just the last message sent in the chat. 我创建了一个lastMessage节点来捕获聊天中发送的最后一条消息。 It is just updated every time a new message is sent in a chat between two users. 每次在两个用户之间的聊天中发送新消息时,它都会更新。 Makes it easy to get the value. 使得获得价值变得容易。 Also makes it easy to show the message on the Conversations screen where there is a list of users who are in a conversation with the current user. 还可以轻松地在“对话”屏幕上显示消息,其中有一个与当前用户进行对话的用户列表。

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);
    });     
});

To implement this logic on your current data structure, just change this line: 要在当前数据结构上实现此逻辑,只需更改此行:

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

and this line: 这一行:

    exports.newMessagePush = 

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

to your token location: 到您的令牌位置:

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

and your conversation location: 和你的谈话地点:

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

Then just change the notification payload be the message you want to display and throw in your error handling on the end of the sendToDevice function, as you did in your code. 然后只需将通知有效负载更改为您要显示的消息,并在sendToDevice函数的末尾引入错误处理,就像在代码中一样。

Hopefully you figured all this out already but if not maybe this will help you or others trying to use Cloud Functions for notifications. 希望你已经知道所有这些,但如果没有,这可能会帮助你或其他人尝试使用云功能进行通知。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何为 onSubmit function 从 firebase v9 获取/建立实时数据连接? - How to fetch/make realtime data connection from firebase v9 for the onSubmit function? 使用 Firebase 云函数从 firebase 发送推送通知 - Send push notification From firebase by using Firebase cloud Functions 是否可以从Firebase控制台发送Firebase Web推送通知 - Is there a way to send firebase web push notification from the firebase console 如何在 firebase function 上为 Z5ACEBC4CB70DDBB6AE74B0AC76AAB1 通知推送创建 Firebase 推送通知有效负载? - How to create Firebase push Notification Payload on firebase function for flutter push Notification? 如何使用 fetch 获取从 Firebase Function 返回的数据? - How to get data returned from a Firebase Function using fetch? 将数据发送到Firebase:data.push()不是函数 - Sending data to firebase: data.push() is not a function "Firebase 无法从数据库“db.collection 不是函数”中检索数据" - Firebase cannot retrieve data from database "db.collection is not a function" firebase 数据库推送通知改变 - Push notification on firebase database changed Firebase云功能,用于使用主题发送推送通知 - Firebase cloud function for sending push notification using topic 带有 typeof 函数的 Firebase 推送数据返回错误 - Firebase push data with typeof function is return an error
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM