javascript - Firebase 云消息传递 sendToDevice 工作正常,但 sendMulticast 对于相同的 token 列表失败

标签 javascript firebase firebase-cloud-messaging apple-push-notifications

对于某些类型的消息,我想通过存储在我的实时数据库中的 FIRTokens 与主题来定位用户。我使用 async/await 加载这些 token ,然后决定是要将通知发送到某个主题还是要发送给较小的用户列表。数据加载代码按预期工作。但奇怪的是,如果我使用 .sendMulticast(payload),列表中所有标记的通知都会失败。另一方面,如果我使用 .sendToDevice(adminFIRTokens, payload),通知会成功发送到我的所有用户。现在我的列表有 2 个标记,使用 sendMulticast 我有 2 次失败,使用 sendToDevice 我有 2 次成功。我错过了 sendMulticast 应该做什么的要点吗?根据the docs: Send messages to multiple devices :

The REST API and the Admin FCM APIs allow you to multicast a message to a list of device registration tokens. You can specify up to 500 device registration tokens per invocation.

所以两者在逻辑上都应该有效。那为什么一个失败而另一个工作呢?事实上,使用 sendToDevice 我在响应中得到了一个 multicastId!

这里是一些控制台输出:

  1. 发送到设备:
Sent filtered message notification successfully: 
{ 
  results: 
    [ 
      { messageId: '0:1...45' }, 
      { messageId: '16...55' } 
    ], 
    canonicalRegistrationTokenCount: 0, 
    failureCount: 0, 
    successCount: 2, 
    multicastId: 3008...7000 
} 
  1. 发送多播:
List of tokens that caused failures: dJP03n-RC_Y:...MvPkTbuV,fDo1S8jPbCM:...2YETyXef 

发送通知的云功能:

functions.database
  .ref("/discussionMessages/{autoId}/")
  .onCreate(async (snapshot, context) => {
    // console.log("Snapshot: ", snapshot);

    try {
      const groupsRef = admin.database().ref("people/groups");
      const adminUsersRef = groupsRef.child("admin");
      const filteredUsersRef = groupsRef.child("filtered");
      const filteredUsersSnapshot = await filteredUsersRef.once("value");
      const adminUsersSnapshot = await adminUsersRef.once("value");
      var adminUsersFIRTokens = {};
      var filteredUsersFIRTokens = {};

      if (filteredUsersSnapshot.exists()) {
        filteredUsersFIRTokens = filteredUsersSnapshot.val();
      }
      if (adminUsersSnapshot.exists()) {
        adminUsersFIRTokens = adminUsersSnapshot.val();
      }

      const topicName = "SpeechDrillDiscussions";
      const message = snapshot.val();
      const senderName = message.userName;
      const senderCountry = message.userCountryEmoji;
      const title = senderName + " " + senderCountry;
      const messageText = message.message;
      const messageTimestamp = message.messageTimestamp.toString();
      const messageID = message.hasOwnProperty("messageID")
        ? message.messageID
        : undefined;
      const senderEmailId = message.userEmailAddress;
      const senderUserName = getUserNameFromEmail(senderEmailId);

      const isSenderFiltered = filteredUsersFIRTokens.hasOwnProperty(
        senderUserName
      );

      var payload = {
        notification: {
          title: title,
          body: messageText,
          sound: "default",
        },
        data: {
          messageID: messageID,
          messageTimestamp: messageTimestamp,
        },
      };

      if (isSenderFiltered) {
        adminFIRTokens = Object.values(adminUsersFIRTokens);
        // payload.tokens = adminFIRTokens; //Needed for sendMulticast
        return (
          admin
            .messaging()
            .sendToDevice(adminFIRTokens, payload)
            // .sendMulticast(payload)
            .then(function (response) {
              if (response.failureCount === 0) {
                console.log(
                  "Sent filtered message notification successfully:",
                  response
                );
              } else {
                console.log(
                  "Sending filtered message notification failed for some tokens:",
                  response
                );
              }
              // if (response.failureCount > 0) {
              //   const failedTokens = [];
              //   response.responses.forEach((resp, idx) => {
              //     if (!resp.success) {
              //       failedTokens.push(adminFIRTokens[idx]);
              //     }
              //   });
              //   console.log(
              //     "List of tokens that caused failures: " + failedTokens
              //   );
              // }

              return true;
            })
        );
      } else {
        payload.topic = topicName;
        return admin
          .messaging()
          .send(payload)
          .then(function (response) {
            console.log("Notification sent successfully:", response);
            return true;
          });
      }
    } catch (error) {
      console.log("Notification sent failed:", error);
      return false;
    }
  });

最佳答案

我认为这是使用不同的有效负载结构的问题。

这是旧的(没有 iOS 特定信息):

var payload = {
    notification: {
      title: title,
      body: messageText,
      sound: "default",
    },
    data: {
      messageID: messageID,
      messageTimestamp: messageTimestamp,
    },
  };

而这是新版本(apns 具有 iOS 特定信息)

var payload = {
    notification: {
      title: title,
      body: messageText,
    },
    data: {
      messageID: messageID,
      messageTimestamp: messageTimestamp,
    },
    apns: {
      payload: {
        aps: {
          sound: "default",
        },
      },
    },
  };

使用新结构,sendsendMulticast 都可以正常工作。这将无法发送或给出错误,例如负载不支持 apns key 。

新功能:

functions.database
  .ref("/discussionMessages/{autoId}/")
  .onCreate(async (snapshot, context) => {
    // console.log("Snapshot: ", snapshot);

    try {
      const groupsRef = admin.database().ref("people/groups");
      const adminUsersRef = groupsRef.child("admin");
      const filteredUsersRef = groupsRef.child("filtered");
      const filteredUsersSnapshot = await filteredUsersRef.once("value");
      const adminUsersSnapshot = await adminUsersRef.once("value");
      var adminUsersFIRTokens = {};
      var filteredUsersFIRTokens = {};

      if (filteredUsersSnapshot.exists()) {
        filteredUsersFIRTokens = filteredUsersSnapshot.val();
      }
      if (adminUsersSnapshot.exists()) {
        adminUsersFIRTokens = adminUsersSnapshot.val();
      }

      // console.log(
      //   "Admin and Filtered Users: ",
      //   adminUsersFIRTokens,
      //   " ",
      //   filteredUsersFIRTokens
      // );

      const topicName = "SpeechDrillDiscussions";
      const message = snapshot.val();

      // console.log("Received new message: ", message);

      const senderName = message.userName;
      const senderCountry = message.userCountryEmoji;
      const title = senderName + " " + senderCountry;
      const messageText = message.message;
      const messageTimestamp = message.messageTimestamp.toString();
      const messageID = message.hasOwnProperty("messageID")
        ? message.messageID
        : undefined;
      const senderEmailId = message.userEmailAddress;
      const senderUserName = getUserNameFromEmail(senderEmailId);

      const isSenderFiltered = filteredUsersFIRTokens.hasOwnProperty(
        senderUserName
      );

      console.log(
        "Will attempt to send notification for message with message id: ",
        messageID
      );

      var payload = {
        notification: {
          title: title,
          body: messageText,
        },
        data: {
          messageID: messageID,
          messageTimestamp: messageTimestamp,
        },
        apns: {
          payload: {
            aps: {
              sound: "default",
            },
          },
        },
      };
      console.log("Is sender filtered? ", isSenderFiltered);

      if (isSenderFiltered) {
        adminFIRTokens = Object.values(adminUsersFIRTokens);
        console.log("Sending filtered notification with sendMulticast()");
        payload.tokens = adminFIRTokens; //Needed for sendMulticast
        return admin
          .messaging()
          .sendMulticast(payload)
          .then((response) => {
            console.log(
              "Sent filtered message (using sendMulticast) notification: ",
              JSON.stringify(response)
            );
            if (response.failureCount > 0) {
              const failedTokens = [];
              response.responses.forEach((resp, idx) => {
                if (!resp.success) {
                  failedTokens.push(adminFIRTokens[idx]);
                }
              });
              console.log(
                "List of tokens that caused failures: " + failedTokens
              );
            }
            return true;
          });
      } else {
        console.log("Sending topic message with send()");
        payload.topic = topicName;
        return admin
          .messaging()
          .send(payload)
          .then((response) => {
            console.log(
              "Sent topic message (using send) notification: ",
              JSON.stringify(response)
            );
            return true;
          });
      }
    } catch (error) {
      console.log("Notification sent failed:", error);
      return false;
    }
  });

关于javascript - Firebase 云消息传递 sendToDevice 工作正常,但 sendMulticast 对于相同的 token 列表失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66075132/

相关文章:

javascript - 面向对象的Javascript中公共(public)函数和使用原型(prototype)添加的函数有什么区别

javascript - 为什么 Firefox 或 Chrome 无法确定 .json 文件的类型?

javascript - Firebase + Node.js : Error: The XMLHttpRequest compatibility library was not found

android - 应用程序在后台时未调用 Firebase onMessageReceived

node.js - 在每次执行时发送多个推送通知的 Firebase 函数中*返回*什么?

javascript - 如何使用 jQuery validate 验证预填充的输入字段?

javascript - 无法使用 .show() 显示隐藏图像

firebase - 在 Flutter 中,我们如何使用 Firebase Messaging onBackgroundMessage 创建通知,使用 flutter_local_notifications?

javascript - 在 firebase 中使用带有 .on() 的 catch() 时出错

ios - 如何在后台收到通知时显示警报和播放声音