user8730776
user8730776

Reputation:

Firebase cloud function doesn't send push notification with async

My goal is to send a push notification when a user sends a message. I am trying to do this by retrieving all of the push tokens from the firestore database, and sending a multicast message using these tokens each time a new message is added to the realtime database.

Works

This first example works. There is no token retrieval, the tokens are hardcoded. I do receive the notifications.

exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate((liveSnapshot, context) => {
    const name = context.params.messageId;
    const message = liveSnapshot.val().toString();
    const tokens = [
         "e6erA_qM...",
         "ePU9p_CI...",
    ];
    const payload = {
        notification: {
            title: `New message from ${name}`,
            body: message,
            badge: '1',
            sound: 'default'
        },
        tokens: tokens,
    }
    const res = admin.messaging().sendMulticast(payload);   
    console.log(`response: ${res}`);

Doesn't work

This doesn't work, I don't receive any notifications.

exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate(async (liveSnapshot, context) => {
    const name = context.params.messageId;
    const message = liveSnapshot.val().toString();
    const snapshot = await admin.firestore().collection('users').get();
    const tokens = snapshot.docs.map(doc => doc.data().token);
    const payload = {
        notification: {
            title: `New message from ${name}`,
            body: message,
            badge: '1',
            sound: 'default'
        },
        tokens: tokens,
    }
    const res = await admin.messaging().sendMulticast(payload);     
    console.log(`response: ${res}`);

I have verified that the tokens retrieved from the database are the same as the hardcoded ones with the following code.

exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate(async (liveSnapshot, context) => {
    const hardcodedTokens = [
         "e6erA_qM...",
         "ePU9p_CI...",
    ];
    const snapshot = await admin.firestore().collection('users').get();
    const tokens = snapshot.docs.map(doc => doc.data().token);
    let same = true;
    hardcodedTokens.forEach(el => {
        if (!tokens.includes(el)) {
           same = false;
        }
    });
    console.log(same);
})

This logs true in the firebase cloud functions console.


The function uses Node 12.

Upvotes: 3

Views: 2357

Answers (2)

jon
jon

Reputation: 3610

I experienced a similar problem recently, and solved it by breaking out Android and iOS specific fields according to the Firebase docs :

   const message = {
  "notification": {
    "title": `New message from ${name}`,
    "body": message,
  },
  'apns': {
    'payload': {
      'aps': {
        'badge': 1,
      },
    },
  },
  'android':{
    'notification':{
      'notificationCount': 1,
    },
  },
  "tokens": tokens,
}

Upvotes: 1

user8730776
user8730776

Reputation:

The following code works.

async function getTokens() {
    const snapshot = await admin.firestore().collection('users').get();
    return snapshot.docs.map(doc => doc.data().token);
}

exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate(async (snapshot, context) => {
    const name = context.params.messageId;
    const message = snapshot.val().toString();
    const tokens = await getTokens();
    const payload = {
        notification: {
            title: `New message from ${name}`,
            body: message,
        },
        tokens: tokens,
    };
    await admin.messaging().sendMulticast(payload);
})

I logged my response like below:

const res = await admin.messaging().sendMulticast(payload);
console.log('response:', JSON.stringify(res));

This logged the following:
response: {"responses":[{"success":false,"error":{"code":"messaging/invalid-argument","message":"Invalid JSON payload received. Unknown name \"sound\" at 'message.notification': Cannot find field."}},{"success":false,"error":{"code":"messaging/invalid-argument","message":"Invalid JSON payload received. Unknown name \"sound\" at 'message.notification': Cannot find field."}}],"successCount":0,"failureCount":2}

Based on this, I believe the problem was the sound argument in the notification part of the payload. It works after removing it.

Upvotes: 1

Related Questions