英文:
Firebase Cloud Function to trigger Firebase Messaging not sending Notification
问题
我想在名为notifications
的用户集合中添加文档时,通过云消息传递发送PushNotification
。根据文档建议,我将用户的token
保存在名为messagingTokens
的字段的arrayUnion
中。
此外,只有当名为isPushEnabled
的字段为true时,才应发送通知。根据这个信息,我构建了以下cloud function
并成功部署了它:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { onDocumentCreated } = require("firebase-functions/v2/firestore");
const { setGlobalOptions } = require("firebase-functions/v2");
admin.initializeApp();
// 将所有函数的最大实例数设置为10
setGlobalOptions({ maxInstances: 10 });
const notificationPath = "allUsers/{userId}/notifications/{notificationId}";
exports.sendNotification = onDocumentCreated(notificationPath, async (event) => {
functions.logger.log("新的通知文档已创建");
const data = event.data.after.data();
const senderUid = data.senderUid;
const receiverUid = data.receiverUid;
const notificationOption = data.option;
functions.logger.log("检索到通知字段");
if (notificationOption === "receivedFriendRequest") {
functions.logger.log("选项为:receivedFriendRequest");
await onSentFriendRequest(senderUid, receiverUid);
}
});
async function onSentFriendRequest(ownerId, userId) {
// 获取所有者的详细信息
const owner = await admin.firestore().collection("allUsers").doc(ownerId).get();
// 获取用户的详细信息
const user = await admin.firestore().collection("allUsers").doc(userId).get();
const userHasNotificationsEnabled = user.data().isPushEnabled;
functions.logger.log("如果这不打印出来,那么你的函数没有被调用");
if (!userHasNotificationsEnabled) {
functions.logger.log("用户未启用推送");
return;
}
functions.logger.log("用户已启用推送");
// 将所有token列为一个数组。
tokens = user.data().messagingTokens;
// 对每个token发送消息
const response = await admin.messaging().sendEachForMulticast({
tokens: tokens,
notification: {
title: "New Friend Request",
body: `${owner.data().username} wants to be friends with you.`,
},
data: {
ownerId: ownerId,
userId: userId,
notificationOption: "receivedFriendRequest",
},
});
// 对于每条消息,检查是否有错误。
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
functions.logger.error(
'向以下token发送通知失败:',
tokens[index],
error
);
// 清理不再注册的token。
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
}
正如我所说,部署成功了。但是当向notifications
集合添加文档时,从我的日志中看到了以下内容:
在Firebase控制台
中,我看到函数被触发,但出现了TypeError
错误。
我在这里做错了什么?
如果你需要更多信息,请告诉我。
编辑
我遇到了关于maxScale
的错误,我可以通过在我的index.js
文件中添加以下行来修复它:
setGlobalOptions({maxInstances: 10})
以及在我的firebase.json
中添加以下内容:
"frameworksBackend": {
"region": "us-central1",
"maxInstances": 10
}
英文:
I want to send a PushNotification
via Cloud Messaging when a document is added inside a collection of a user called notifications
. I am saving the token
for the user as suggested in the docs in a arrayUnion
in a field called messagingTokens
.
Additionally the notification should only be sent if a field called isPushEnabled
is true. With this information I build this cloud function
and successfully deployed it:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { onDocumentCreated } = require("firebase-functions/v2/firestore");
const { setGlobalOptions } = require("firebase-functions/v2");
admin.initializeApp();
// Set the maximum instances to 10 for all functions
setGlobalOptions({ maxInstances: 10 });
const notificationPath = "allUsers/{userId}/notifications/{notificationId}";
exports.sendNotification = onDocumentCreated(notificationPath, async (event) => {
functions.logger.log("New notificatin document was created");
const data = event.data.after.data();
const senderUid = data.senderUid;
const receiverUid = data.receiverUid;
const notificationOption = data.option;
functions.logger.log("Retrieved notification fields");
if (notificationOption === "receivedFriendRequest") {
functions.logger.log("Is option: receivedFriendRequest");
await onSentFriendRequest(senderUid, receiverUid);
}
});
async function onSentFriendRequest(ownerId, userId) {
// Get the owners details
const owner = await admin.firestore().collection("allUsers").doc(ownerId).get();
// Get the users details
const user = await admin.firestore().collection("allUsers").doc(userId).get();
const userHasNotificationsEnabled = user.data().isPushEnabled;
functions.logger.log("If this does not print, then your function is not being called");
if (!userHasNotificationsEnabled) {
functions.logger.log("User does not have push enabled");
return;
}
functions.logger.log("User has push enabled");
// Listing all tokens as an array.
tokens = user.data().messagingTokens;
// Send message to all tokens
const response = await admin.messaging().sendEachForMulticast({
tokens: tokens,
notification: {
title: "Neue Freundschaftsanfrage",
body: `${owner.data().username} möchte mit dir befreundet sein.`,
},
data: {
ownerId: ownerId,
userId: userId,
notificationOption: "receivedFriendRequest",
},
});
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
functions.logger.error(
'Failure sending notification to',
tokens[index],
error
);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
}
Like I said, the deployment was successful. But when a document is added to the notifications
-collection I get this from my logs:
Inside the Firebase-Console
I see that the function was triggered, I get a TypeError
.
What am I doing wrong here?
Let me know if you need more information.
EDIT
I had an error about maxScale
which I could fix by adding this line inside my index.js
-file:
setGlobalOptions({maxInstances: 10})
and this inside my firebase.json
:
"frameworksBackend": {
"region": "us-central1",
"maxInstances": 10
}
答案1
得分: 1
我已经搞定了。我的代码中有一些小问题,比如拼写错误或答案中建议的改进。
通过查看这个示例代码,以及查看doc
中的sendEachForMultiCast
和onDocumentCreated
,我能够使用以下代码使其工作:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { onDocumentCreated } = require("firebase-functions/v2/firestore");
const { setGlobalOptions } = require("firebase-functions/v2");
admin.initializeApp();
// 设置所有函数的最大实例数为10
setGlobalOptions({ maxInstances: 10 });
const notificationPath = "allUsers/{userId}/notifications/{notificationId}";
exports.sendNotification = onDocumentCreated(notificationPath, async (event) => {
functions.logger.log("新的通知文档已创建");
const snapshot = event.data;
if (!snapshot) {
console.log("与事件关联的数据为空");
return;
}
const data = snapshot.data();
// 与访问任何 JS 属性一样访问特定字段
const name = data.name;
const senderUid = data.senderUid;
const receiverUid = data.receiverUid;
const notificationOption = data.option;
if (notificationOption === "receivedFriendRequest") {
await onSentFriendRequest(senderUid, receiverUid);
} else {
functions.logger.log(`通知选项是: ${notificationOption}`);
}
});
async function onSentFriendRequest(ownerId, userId) {
// 获取所有者的详细信息
const owner = await admin.firestore().collection("allUsers").doc(ownerId).get();
// 获取用户的详细信息
const user = await admin.firestore().collection("allUsers").doc(userId).get();
const userHasNotificationsEnabled = user.data().isPushEnabled;
if (!userHasNotificationsEnabled) {
functions.logger.log("用户未启用推送通知");
return;
}
// 将所有令牌列为数组。
tokens = user.data().messagingTokens;
// 向所有令牌发送消息
const response = await admin.messaging().sendEachForMulticast({
tokens: tokens,
notification: {
title: "新的好友请求",
body: `${owner.data().username} 想要与您成为好友。`,
},
data: {
ownerId: ownerId,
userId: userId,
notificationOption: "receivedFriendRequest",
},
});
functions.logger.log("成功发送通知");
// 对于每条消息,请检查是否有错误。
const tokensToRemove = [];
response.responses.forEach((result, index) => {
const error = result.error;
if (error) {
functions.logger.error(
'向以下令牌发送通知失败:',
tokens[index],
error
);
// 清理不再注册的令牌。
if (error.code === 'messaging/unregistered' ||
error.code === 'messaging/invalid-argument') {
tokensToRemove.push(admin.firestore().collection("allUsers").doc(userId).update({
"messagingTokens": admin.firestore.FieldValue.arrayRemove(tokens[index])
}));
}
}
});
return Promise.all(tokensToRemove);
}
英文:
I got it working. I had smaller issues in my code, like Typos, or the suggested improvements from the answers.
By following this Sample-Code and also looking into doc
for sendEachForMultiCast
and onDocumentCreated
I was able to make it work with this code:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { onDocumentCreated } = require("firebase-functions/v2/firestore");
const { setGlobalOptions } = require("firebase-functions/v2");
admin.initializeApp();
// Set the maximum instances to 10 for all functions
setGlobalOptions({ maxInstances: 10 });
const notificationPath = "allUsers/{userId}/notifications/{notificationId}";
exports.sendNotification = onDocumentCreated(notificationPath, async (event) => {
functions.logger.log("New notificatin document was created");
const snapshot = event.data;
if (!snapshot) {
console.log("No data associated with the event");
return;
}
const data = snapshot.data();
// access a particular field as you would any JS property
const name = data.name;
const senderUid = data.senderUid;
const receiverUid = data.receiverUid;
const notificationOption = data.option;
if (notificationOption === "recievedFriendRequest") {
await onSentFriendRequest(senderUid, receiverUid);
} else {
functions.logger.log(`is notificationOption: ${notificationOption}`);
}
});
async function onSentFriendRequest(ownerId, userId) {
// Get the owners details
const owner = await admin.firestore().collection("allUsers").doc(ownerId).get();
// Get the users details
const user = await admin.firestore().collection("allUsers").doc(userId).get();
const userHasNotificationsEnabled = user.data().isPushEnabled;
if (!userHasNotificationsEnabled) {
functions.logger.log("User does not have push enabled");
return;
}
// Listing all tokens as an array.
tokens = user.data().messagingTokens;
// Send message to all tokens
const response = await admin.messaging().sendEachForMulticast({
tokens: tokens,
notification: {
title: "Neue Freundschaftsanfrage",
body: `${owner.data().username} möchte mit dir befreundet sein.`,
},
data: {
ownerId: ownerId,
userId: userId,
notificationOption: "receivedFriendRequest",
},
});
functions.logger.log("Successflully send Notification");
// For each message check if there was an error.
const tokensToRemove = [];
response.responses.forEach((result, index) => {
const error = result.error;
if (error) {
functions.logger.error(
'Failure sending notification to',
tokens[index],
error
);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/unregistered' ||
error.code === 'messaging/invalid-argument') {
tokensToRemove.push(admin.firestore().collection("allUsers").doc(userId).update({
"messagingTokens": admin.firestore.FieldValue.arrayRemove(tokens[index])
}));
}
}
});
return Promise.all(tokensToRemove);
}
答案2
得分: 0
const admin = require('firebase-admin');
admin.initializeApp();
在使用 Firebase Functions 时,应始终使用 onCreate 触发器来监听文档创建,而不是使用 onDocumentCreated 函数,因为 Firebase Functions SDK 中不存在该函数。以增加的复杂性和变化程度编写代码可以产生更有趣和吸引人的内容,使读者能更好地理解和欣赏他们正在阅读的文字。
exports.sendNotification = functions.firestore
.document(notificationPath)
.onCreate(async (snapshot, context) => {
// 检索文档数据
const data = snapshot.data();
const senderUid = data.senderUid;
const receiverUid = data.receiverUid;
const notificationOption = data.notificationOption;
if (notificationOption === "receivedFriendRequest") {
await onSentFriendRequest(senderUid, receiverUid);
}
});
在您的代码中更新用户令牌是必不可少的。为了检索用户的 messagingTokens,代码需要获取 Firestore 文档快照并考虑 messagingTokens 字段。为此,应更改代码如下:使用 user.data().messagingTokens 而不是 user.messagingTokens。
const userHasNotificationsEnabled = user.data().isPushEnabled;
if (userHasNotificationsEnabled) {
const tokens = user.data().messagingTokens;
await admin.messaging().sendMulticast({
tokens: tokens,
notification: {
title: "Neue Freundschaftsanfrage",
body: `${owner.data().userName} möchte mit dir befreundet sein.`,
},
data: {
ownerId: ownerId,
userId: userId,
notificationOption: "receivedFriendRequest",
},
});
}
您可以在相关点添加 console.log 语句。
console.log("用户已启用推送通知");
希望这有所帮助!
英文:
const admin = require('firebase-admin');
admin.initializeApp();
When working with Firebase Functions, you should always use the onCreate trigger to listen for document creations instead of the onDocumentCreated function, since it does not exist in the Firebase Functions SDK. Writing with an increased degree of complexity and variation can lead to much more interesting and engaging content, allowing readers to better understand and appreciate the words they are consuming.
exports.sendNotification = functions.firestore
.document(notificationPath)
.onCreate(async (snapshot, context) => {
// Retrieve the document data
const data = snapshot.data();
const senderUid = data.senderUid;
const receiverUid = data.receiverUid;
const notificationOption = data.notificationOption;
if (notificationOption === "receivedFriendRequest") {
await onSentFriendRequest(senderUid, receiverUid);
}
});
Updating user tokens in your code is essential. To retrieve a user's messagingTokens, the code needs to take a Firestore document snapshot and account for the messagingTokens field. To do that, user.data().messagingTokens must be used. Therefore, the code should be changed as follows: user.data().messagingTokens instead of user.messagingTokens.
const userHasNotificationsEnabled = user.data().isPushEnabled;
if (userHasNotificationsEnabled) {
const tokens = user.data().messagingTokens;
await admin.messaging().sendMulticast({
tokens: tokens,
notification: {
title: "Neue Freundschaftsanfrage",
body: `${owner.data().userName} möchte mit dir befreundet sein.`,
},
data: {
ownerId: ownerId,
userId: userId,
notificationOption: "receivedFriendRequest",
},
});
}
you can add console.log statement at relevant points.
console.log("User has push enabled");
Hope this helps!
答案3
得分: 0
从文档中可以看到,admin.messaging().send(message: Message, dryRun?: boolean)
接受两个参数,即message
和dryRun
,不接受令牌。您应该将令牌添加到消息中。
functions.logger.log("如果这不打印出来,那么您的函数没有被调用");
if (!userHasNotificationsEnabled) {
functions.logger.log("用户没有启用推送");
return;
}
functions.logger.log("用户已启用推送");
const message = {
notification: {
title: "新的朋友请求",
body: owner.userName + " 想要成为您的朋友。",
},
data: {
ownerId: ownerId,
userId: userId,
notificationOption: "收到朋友请求",
},
token: user.messagingTokens.first, // 令牌应该是一个字符串
};
functions.logger.log(message);
await admin.messaging().send(message);
另外,考虑使用.onCreate(
而不是onDocumentCreated(
。
英文:
From the docs, admin.messaging().send(message: Message, dryRun?: boolean)
takes in 2 parameters, i.e, message and dryRun. It does not take the token. You should add the token to the message.
functions.logger.log("If this does not print, then your function is not being called");
if (!userHasNotificationsEnabled) {
functions.logger.log("User does not have push enabled");
return;
}
functions.logger.log("User has push enabled");
const message = {
notification: {
title: "Neue Freundschaftsanfrage",
body: owner.userName + " möchte mit dir befreundet sein.",
},
data: {
ownerId: ownerId,
userId: userId,
notificationOption: "recievedFriendRequest",
},
token: user.messagingTokens.first, // token should be a single string
};
functions.logger.log(message);
await admin.messaging().send(message);
Also, consider using .onCreate(
instead of onDocumentCreated(
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论