Функции Firebase уведомление об отправке облачных сообщений не получено

# #firebase #flutter #google-cloud-functions #firebase-cloud-messaging

Вопрос:

Когда я отправляю уведомление с консоли обмена сообщениями Firebase cloud, мое устройство получает его без проблем, но когда я отправляю его через облачные функции, в журнале функций говорится, что оно было успешно отправлено, но мое устройство его не получает. Я попытался переключиться на скрипт ввода, отправив уведомление с другими условиями, но ничего не работает. Приложение написано на языке 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; 
});
 

облачный журнал

Есть какие-нибудь идеи?

Ответ №1:

Вы заметили, что ваш код никогда не регистрирует это сообщение?

Успешно отправленное сообщение

Это связано с тем, что как загрузка из Firestore, так и отправка сообщений через облачные сообщения являются асинхронными вызовами. Таким образом, вы response.send("Notification sent !") запускаетесь до того, как данные будут извлечены из базы данных, и облачные функции в этот момент завершают ваш код, чтобы предотвратить зарядку после того, как вы скажете, что закончили.

Если в вашем коде есть асинхронные операции, вам необходимо вернуть обещание с верхнего уровня кода, которое будет разрешено/отклонено после завершения всего асинхронного кода. Таким образом, в вашем случае это означает, что обещание должно быть выполнено только после того, как вы загрузили данные из Firestore и отправили сообщения.


Давайте начнем с простого примера. Скажите, что вы хотите отправить только одно сообщение, независимо от того, сколько документов находится в базе данных.

 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};
                });
            }
        });
});
 

Таким образом, код верхнего уровня теперь возвращает результат загрузки данных из Firestore, и там мы возвращаем вызов от вызова FCM, который затем, в свою очередь, возвращается return {success: true}; . При возврате обещаний результаты всплывают — так что обычно вы можете просто продолжать возвращать вложенные результаты.

Вы также не заметите, что мы переместили код response.send в код, который запускается после вызова FCM, так как мы не хотим отправлять результат обратно вызывающему абоненту, пока вызов FCM не будет выполнен.


Вышеописанный вариант является простым, потому что на самом деле у вас есть несколько документов, и вы закончите только после того, как все они будут выполнены.

Для этого мы собираемся использовать Promise.all() , который принимает множество обещаний и решает, как только все эти обещания разрешатся. Поэтому мы собираемся захватить все вызовы FCM (который возвращает обещание) и собрать их в массив, который мы затем передадим 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};
            });
        }
    });
});
 

Хотя это может быть непросто сделать сразу, обработка асинхронного поведения довольно хорошо описана в документации Firebase по завершающим функциям, в этой серии видеороликов, посвященных изучению обещаний JavaScript с облачными функциями, и в нескольких учебных пособиях, поэтому я рекомендую потратить некоторое время на них, чтобы разобраться с асинхронным кодом.

Комментарии:

1. БОЛЬШОЕ ВАМ СПАСИБО, ЭТО ПРЕКРАСНО РАБОТАЕТ! Я не мог свыкнуться с мыслью об обещаниях. Другой вопрос, существует ли эффективный способ перебора, например, 400 документов firestore ? Могу ли я сделать это с помощью promises.push аналогично отправке полезной нагрузки?