简体   繁体   中英

Firebase Cloud Messaging for sending notification to all the registered devices not working

For my magazine app,I am using Firebase service.One function of this android app is whenever new article is published;notification of new article is sent to all the devices.

I am saving all the device tokens in db like this: FCMToken { userid:deviceToken }

So whenever new node is added in "published" key in firebase db,FCM function is triggered and messages is sent to all the devices:

Below is my code in javascript for FCM function:

'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/published/{msg_id}').onWrite(event => {
  const snapshot = event.data;
  // Only send a notification when a new message has been created.
  if (snapshot.previous.val()) {
    return;
  }
  const msg_id = event.params.msg_id;

  const msg_val=admin.database().ref(`messages/${msg_id}`).once('value');
  return msg_val.then(msgResult =>{
    const msg_title=msgResult.val().title;
    const user_id=msgResult.val().userId;
    console.log('msg title is',msg_title);
     console.log('We have a new article : ', msg_id);
      const payload={

        data : {
          title:"New Article",
          body: msg_title,
          msgid : msg_id,
          userid : user_id

        }
    };


 // const deviceToken = admin.database().ref('/FCMToken/{user_id}').once('value');
admin.database().ref('/FCMToken').on("value", function(dbsnapshot)
{
  dbsnapshot.forEach(function(childSnapshot) {
    //var childKey = childSnapshot.key;
    const childData = childSnapshot.val();
    const deviceToken=console.log("device token" + childSnapshot.val());


    return admin.messaging().sendToDevice(childData,payload).then(response=>{
      console.log("This was notification feature")
      console.log("response: ", response);
    })
    .catch(function(error)
    {
      console.log("error sending message",error)
    });
  });
  });

  });

});

For some reason,notification is only sent to only 1 device(the first token in FCM node). Update: I have updated my code and using promise,but for some reason it is still not working,just sending notification to first device token.

'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/published/{msg_id}').onWrite(event => {
  const snapshot = event.data;
  // Only send a notification when a new message has been created.
  if (snapshot.previous.val()) {
    return;
  }
  const msg_id = event.params.msg_id;

  const msg_val=admin.database().ref(`messages/${msg_id}`).once('value');
  return msg_val.then(msgResult =>{
    const msg_title=msgResult.val().title;
    const user_id=msgResult.val().userId;
    console.log('msg title is',msg_title);
     console.log('We have a new article : ', msg_id);
      const payload={

        data : {
          title:"New Article",
          body: msg_title,
          msgid : msg_id,
          userid : user_id

        }
    };

const promises=[];

 // const deviceToken = admin.database().ref('/FCMToken/{user_id}').once('value');
admin.database().ref('/FCMToken').once('value').then(function(dbsnapshot)
{

  dbsnapshot.forEach(function(childSnapshot) {
    //var childKey = childSnapshot.key;
    const childData = childSnapshot.val();
    const deviceToken=console.log("device token" + childSnapshot.val());


    const promise = admin.messaging().sendToDevice(childData,payload).then(response=>{
    promises.push(promise)
      console.log("This was notification feature")
      console.log("response: ", response);
    })
    return Promise.all(promises)
    .catch(function(error)
    {
      console.log("error sending message",error)
    });
  });
  });

  });

});

Response object is giving this output: response: { results: [ { error: [Object] } ], canonicalRegistrationTokenCount: 0, failureCount: 1, successCount: 0, multicastId: 6411440389982586000 }

You're not using promises correctly throughout your function. There are two things wrong.

First, you should be querying the database using once() instead of on() , and using the promise returned from it in order to proceed to the next item of work:

admin.database().ref('/FCMToken').on("value")
.then(result => /* continue your work here */)

Also, you can't return a promise out of the forEach loop. Instead, you need to return a promise at the top level of the function, as the very last step in the function. This promise needs to resolve when all of the work is done in this function. For your function, this means when all of the messages are sent. You'll have to collect all the promises for all of the messages in an array, then return a single promise that resolves when they all resolve. The general form of that looks like this:

const promises = []

dbsnapshot.forEach(function(childSnapshot) {
    // remember each promise for each message sent
    const promise = return admin.messaging().sendToDevice(...)
    promises.push(promise)
})

// return a single promise that resolves when everything is done
return Promise.all(promises)

Please take care to learn how promises work in JavaScript. You won't be able to write effective functions without dealing with promises correctly.

So I figured out another method to get values. const tokens= Object.keys(tokensSnapshot.val()).map(e => tokensSnapshot.val()[e]);

Below is my complete method:

'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
//Object.values = require('object.values');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/published/{msg_id}').onWrite(event => {
  const snapshot = event.data;
  // Only send a notification when a new message has been created.
  if (snapshot.previous.val()) {
    return;
  }
  const msg_id = event.params.msg_id;

  const msg_val=admin.database().ref(`messages/${msg_id}`).once('value');
  return msg_val.then(msgResult =>{
    const msg_title=msgResult.val().title;
    const user_id=msgResult.val().userId;
    console.log('msg title is',msg_title);
     console.log('We have a new article : ', msg_id);
      const payload={

        data : {
          title:"New Article",
          body: msg_title,
          msgid : msg_id,
          userid : user_id

        }
    };




 const getDeviceTokensPromise = admin.database().ref('/FCMToken').once('value');
 return Promise.all([getDeviceTokensPromise, msg_title]).then(results => {


   const tokensSnapshot = results[0];
    const msgi = results[1];

  if (!tokensSnapshot.hasChildren()) {
      return console.log('There are no notification tokens to send to.');
    }
    console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
    console.log("tokenslist",tokensSnapshot.val());
   const tokens= Object.keys(tokensSnapshot.val()).map(e => tokensSnapshot.val()[e]);
   //var values = Object.keys(o).map(e => obj[e])


     return admin.messaging().sendToDevice(tokens, payload).then(response => {
      // For each message check if there was an error.
      const tokensToRemove = [];
      response.results.forEach((result, index) => {
        const error = result.error;
        if (error) {
          console.error('Failure sending notification to', tokens[index], error);
          // Cleanup the tokens who are not registered anymore.

        }
      });
      return Promise.all(tokensToRemove);
    });

});
});
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM