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

时间:2017-12-20 00:35:06

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

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

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

  1. 消息
  2. Message_From
  3. 时间
  4. 类型
  5. token_To
  6. Firebase database structure

    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功能日志

    Firebase cloud function Log

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

    先谢谢。

4 个答案:

答案 0 :(得分:2)

我所做的是创建了一个Message节点,我相信用户密钥可以做到这一点。即,使接收者(toId)和发送者(fromId)密钥发送通知。 希望它有所帮助。

Firebase message node

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

答案 1 :(得分:1)

const getDeviceTokensPromise = event.data.child('token_To');

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

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

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

其中聊天室和中间变量包含值

第二件事:

if (!tokensSnapshot.exists()) { 

应该取代

if (!tokensSnapshot.hasChildren()) {

第三件事:

我不确定推送通知tokenId但是 它需要做什么?

  

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

我们可以直接使用如下方式发送推送通知

const tokens = tokensSnapshot.val();

答案 2 :(得分:0)

 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修复有效负载。对于Data FCM,您必须在FCM服务(客户端)中提取数据,并根据您的需要生成推送通知。

答案 3 :(得分:0)

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

这适用于Andriod和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函数末尾引入错误处理,就像在代码中一样。

希望您已经知道所有这些,但如果没有,这可能会帮助您或其他人尝试使用云功能进行通知。