Firebase云函数触发Firebase消息未发送通知。

3
我想在用户的“通知”集合中添加文档时,通过“云消息传递”发送“推送通知”。根据文档中的建议,我将用户的“令牌”保存在名为“messagingTokens”的字段的“arrayUnion”中。
此外,只有当名为“isPushEnabled”的字段为true时,才应发送通知。根据这些信息,我构建了这个“云函数”,并成功部署了它:
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);

}

就像我说的那样,部署成功了。但是当一个文档被添加到“notifications”集合中时,我从日志中得到了这个信息:

Logs

Firebase 控制台 中,我看到函数被触发了,但是我遇到了一个 TypeError

我在这里做错了什么?如果需要更多信息,请告诉我。

编辑

关于 maxScale,我有一个错误,我可以通过在我的 index.js 文件中添加这行代码来修复:

    setGlobalOptions({maxInstances: 10})

这是我的firebase.json文件中的内容:
  "frameworksBackend": {
    "region": "us-central1",
    "maxInstances": 10
  }

你的错误信息意味着 data 未定义。最后打印的日志信息是什么?这应该有助于确定哪个数据未定义。 - Peter Obiechina
你的错误信息意味着 data 未定义。最后一条打印的日志信息是什么?这应该有助于确定哪个数据未定义。 - Peter Obiechina
@PeterObiechina "新的通知文档已创建"。 - Chris
@PeterObiechina "新的通知文件已创建"。 - Chris
3个回答

1

我解决了它。我的代码中存在一些小问题,比如拼写错误或来自答案的建议改进。

通过参考这个示例代码,并查看 doc 中的 sendEachForMultiCastonDocumentCreated,我成功让它与以下代码一起工作:

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

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) => {
        // 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);
        }
    });

更新用户令牌在你的代码中是必不可少的。为了获取用户的messagingTokens,代码需要获取一个Firestore文档快照并考虑messagingTokens字段。为了做到这一点,必须使用user.data().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("User has push enabled");

希望这能帮到你!

sendMulticast 已经过时/被弃用。文档:https://firebase.google.com/docs/reference/admin/node/firebase-admin.messaging.messaging.md#messagingsendmulticast - Peter Obiechina
sendMulticast已过时/废弃。文档:https://firebase.google.com/docs/reference/admin/node/firebase-admin.messaging.messaging.md#messagingsendmulticast - Peter Obiechina
我更新了我的问题和代码。目前我正在使用 sendEachForMulticast,但我的代码在那之前出现了错误。你知道为什么吗? - Chris
我更新了我的问题和代码。目前我正在使用sendEachForMulticast,但我的代码在那之前的某个地方出错了。你知道为什么吗? - Chris

0
docs中可以看到,admin.messaging().send(message: Message, dryRun?: boolean)接受两个参数,即message和dryRun。它不接受token。你应该将token添加到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);

另外,考虑使用.onCreate()而不是onDocumentCreated()

为什么我应该考虑使用onCreate而不是onDocumentCreated - Chris
在今天之前,我还没有遇到过onDocumentCreated,并且我认为onDocumentCreated不是来自官方文档。这就是为什么我建议你使用我目前正在使用并且对我有效的onCreate。但是我刚刚搜索了一下,它是来自Firestore v2 API。所以,你可以继续使用它。它不应该引起任何问题。 - Peter Obiechina
如果我的解决方案不起作用,你可以告诉我,我会帮助你调试它。 - Peter Obiechina
我更新了我的问题。我更新了我的代码,但它仍然不起作用:/ 但至少现在我得到了另一个错误。 - Chris
我更新了我的问题。我更新了我的代码,但它仍然不起作用 :/ 但至少现在我得到了另一个错误。 - Chris
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接