最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Firebase function to fetch data from Firebase DB to make Push notification - Stack Overflow

programmeradmin1浏览0评论

I have chat app with firebase database and Firebase cloud messaging. I can send firebase notification via console but in real scenario it should be automatic. To make automatic notification,My friend wrote Index.js (Added in cloud functions) file for me but its not sending notifications.

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).

  1. Message
  2. Message_From
  3. Time
  4. Type
  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: "/"
})

// // Create and Deploy Your First Cloud 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

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

Thanks in Advance.

I have chat app with firebase database and Firebase cloud messaging. I can send firebase notification via console but in real scenario it should be automatic. To make automatic notification,My friend wrote Index.js (Added in cloud functions) file for me but its not sending notifications.

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).

  1. Message
  2. Message_From
  3. Time
  4. Type
  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./"
})

// // Create and Deploy Your First Cloud Functions
// // https://firebase.google./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

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

Thanks in Advance.

Share Improve this question asked Dec 20, 2017 at 0:35 androidXPandroidXP 1,7194 gold badges29 silver badges60 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 2

What i did is created a Message node and I believe doing this by users key. ie, having the receiver(toId) and sender (fromId) key to send the notification. Hope it helps.

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?

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

may be we can use directly like below to send push notification

const tokens = tokensSnapshot.val();

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.

This works for both Andriod and 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. 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.

Hopefully you figured all this out already but if not maybe this will help you or others trying to use Cloud Functions for notifications.

 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. 1) Data 2) Notification

For detailed overview : FCM Reference

You have to fix your payload for both FCMS. And for Data FCM you have to extract Data in your FCM Service (Client) and generate a push notification according to your need.

发布评论

评论列表(0)

  1. 暂无评论