未收到 Firebase 功能云消息通知

Firebase functions cloud messaging notification not being recieved

当我从 Firebase 云消息控制台发送通知时,我的设备可以毫无问题地接收它,但是当我通过云函数发送它时,函数日志显示它已成功发送但我的设备没有收到它.我尝试切换到类型脚本,以不同的条件发送通知,但没有任何效果。该应用程序是用 flutter 编写的。

我的函数代码:

exports.sendNotification = functions.https.onRequest((request, response) => {
    const db = admin.firestore();
    const fcm = admin.messaging();
    db.collection("users")
        .where("bananas", "==", 1666).get().then(
            (result) => {
                if (result.size > 0) {
                    result.forEach((doc) => {
                          const payload = {
                            token: doc.data().NotToken,
                            notification: {
                              title: "iam a notification",
                              body: "Yay",
                              icon: "https://cdn1.iconfinder.com/data/icons/logos-brands-in-colors/231/among-us-player-white-512.png",
                            },
                          };
                          fcm.send(payload).then((response) => {
                            // Response is a message ID string.
                            console.log("Successfully sent message: "+
                            doc.data().NotToken+ "  ", response);
                            return {success: true};
                        }).catch((error) => {
                            return {error: error.code};
                        });
                    });
                }
            });
    response.send("Notification sent !");
    functions.logger.info("Notification sent!");
    return null; 
});

云日志

有什么想法吗?

您是否注意到您的代码从未记录此消息?

Successfully sent message

那是因为从 Firestore 加载和通过 Cloud Messaging 发送消息都是异步调用。因此,您的 response.send("Notification sent !") 在从数据库中检索数据之前运行,此时 Cloud Functions 会终止您的代码,以防止在您说完后收费。

如果您的代码中有异步操作,您需要 return 来自代码顶层的承诺,即 resolves/rejects 当所有异步代码完成时。因此,在您的情况下,这意味着只有在您从 Firestore 加载数据并发送消息后,promise 才应该解析。


让我们从一个简单的例子开始。假设您只想发送一条消息,无论数据库中有多少文档。

exports.sendNotification = functions.https.onRequest((request, response) => {
    const db = admin.firestore();
    const fcm = admin.messaging();
    return db.collection("users") //  Add return here
        .where("bananas", "==", 1666).get().then((result) => {
            if (result.size > 0) {
                const doc = result.docs[0]; //  Get the first result
                  const payload = {
                    token: doc.data().NotToken,
                    notification: {
                      title: "iam a notification",
                      body: "Yay",
                      icon: "https://cdn1.iconfinder.com/data/icons/logos-brands-in-colors/231/among-us-player-white-512.png",
                    },
                  };
                  return fcm.send(payload).then((response) => { //  Add return here
                    console.log("Successfully sent message: "+
                    doc.data().NotToken+ "  ", response);
                    response.send("Notification sent !"); //  Move this call here
                    return {success: true};
                }).catch((error) => {
                    // TODO: Send an error back to the caller
                    return {error: error.code};
                });
            }
        });
});

所以顶级代码现在 return 是从 Firestore 加载数据的结果,在那里,我们 return 调用 FCM,然后又 returns return {success: true};。当 returning 承诺时,结果会冒泡 - 因此您通常可以只保留 returning 嵌套结果。

您也不会认为我们已将 response.send 移动到调用 FCM 后运行的代码中,因为我们不想在 FCM 调用完成之前将结果发送回调用方.


以上是简单的变体,因为在现实中你有多个文档,而且只有在所有文档都完成后你才完成。

为此,我们将使用 Promise.all(),它接受一系列承诺,并在所有这些承诺都解决后解决。因此,我们将捕获对 FCM 的所有调用(return 是一个承诺)并将它们收集在一个数组中,然后我们将其传递给 Promise.all().

exports.sendNotification = functions.https.onRequest((request, response) => {
    const db = admin.firestore();
    const fcm = admin.messaging();
    return db.collection("users")
      .where("bananas", "==", 1666).get().then((result) => {
        if (result.size > 0) {
            let promises = [];
            result.forEach((doc) => {
                const payload = {
                  token: doc.data().NotToken,
                  notification: {
                    title: "iam a notification",
                    body: "Yay",
                    icon: "https://cdn1.iconfinder.com/data/icons/logos-brands-in-colors/231/among-us-player-white-512.png",
                  },
                };
                promises.push(fcm.send(payload))
            });
            return Promise.al(promises).then((results) => {
                console.log("Successfully sent messages");
                response.send("Notification sent !");
                return {success: true};
            });
        }
    });
});

虽然一次要理解很多东西,但处理异步行为在 terminating functions, in this video series on Learn JavaScript Promises with Cloud Functions 上的 Firebase 文档和相当多的教程中有很好的介绍 - 所以我建议花一些时间关于那些掌握异步代码的人。