# #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 аналогично отправке полезной нагрузки?