使用 Expo-server-sdk 的 Firebase 云功能

Firebase cloud function using Expo-server-sdk

我正在尝试使用 Firebase 云功能发送推送通知。

我正在使用 https://github.com/expo/expo-server-sdk-node

当我尝试部署时遇到了一些错误。 (仅在需要早期代码和包时出现错误,而不是在部署我的 hello world 函数时)

代码

const functions = require("firebase-functions");
const { Expo } = require("expo-server-sdk");

// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions

exports.helloWorld = functions.https.onRequest((request, response) => {
  functions.logger.info("Hello logs!", { structuredData: true });
  response.send("Hello from Firebase");
});

exports.notifications = functions.firestore
  .document("notifications/{id}")
  .onCreate((snap, context) => {
    // console.log("-----snap", snap.data());
    // console.log("-----context", context);
    // console.log("-----context.params", context.params);

    // Create a new Expo SDK client
    // optionally providing an access token if you have enabled push security
    let expo = new Expo({ accessToken: process.env.EXPO_ACCESS_TOKEN });

    // Create the messages that you want to send to clients
    let messages = [];
    for (let pushToken of somePushTokens) {
      // Each push token looks like ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]

      // Check that all your push tokens appear to be valid Expo push tokens
      if (!Expo.isExpoPushToken(pushToken)) {
        console.error(`Push token ${pushToken} is not a valid Expo push token`);
        continue;
      }

      // Construct a message (see https://docs.expo.io/push-notifications/sending-notifications/)
      messages.push({
        to: pushToken,
        sound: "default",
        body: "This is a test notification",
        data: { withSome: "data" }
      });
    }

    // The Expo push notification service accepts batches of notifications so
    // that you don't need to send 1000 requests to send 1000 notifications. We
    // recommend you batch your notifications to reduce the number of requests
    // and to compress them (notifications with similar content will get
    // compressed).
    let chunks = expo.chunkPushNotifications(messages);
    let tickets = [];
    (async function test() {
      // Send the chunks to the Expo push notification service. There are
      // different strategies you could use. A simple one is to send one chunk at a
      // time, which nicely spreads the load out over time:
      for (let chunk of chunks) {
        try {
          let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
          console.log(ticketChunk);
          tickets.push(...ticketChunk);
          // NOTE: If a ticket contains an error code in ticket.details.error, you
          // must handle it appropriately. The error codes are listed in the Expo
          // documentation:
          // https://docs.expo.io/push-notifications/sending-notifications/#individual-errors
        } catch (error) {
          console.error(error);
        }
      }
    })();

    // Later, after the Expo push notification service has delivered the
    // notifications to Apple or Google (usually quickly, but allow the the service
    // up to 30 minutes when under load), a "receipt" for each notification is
    // created. The receipts will be available for at least a day; stale receipts
    // are deleted.
    //
    // The ID of each receipt is sent back in the response "ticket" for each
    // notification. In summary, sending a notification produces a ticket, which
    // contains a receipt ID you later use to get the receipt.
    //
    // The receipts may contain error codes to which you must respond. In
    // particular, Apple or Google may block apps that continue to send
    // notifications to devices that have blocked notifications or have uninstalled
    // your app. Expo does not control this policy and sends back the feedback from
    // Apple and Google so you can handle it appropriately.
    let receiptIds = [];
    for (let ticket of tickets) {
      // NOTE: Not all tickets have IDs; for example, tickets for notifications
      // that could not be enqueued will have error information and no receipt ID.
      if (ticket.id) {
        receiptIds.push(ticket.id);
      }
    }

    let receiptIdChunks = expo.chunkPushNotificationReceiptIds(receiptIds);
    (async function testTwo() {
      // Like sending notifications, there are different strategies you could use
      // to retrieve batches of receipts from the Expo service.
      for (let chunk of receiptIdChunks) {
        try {
          let receipts = await expo.getPushNotificationReceiptsAsync(chunk);
          console.log(receipts);

          // The receipts specify whether Apple or Google successfully received the
          // notification and information about an error, if one occurred.
          for (let receiptId in receipts) {
            let { status, message, details } = receipts[receiptId];
            if (status === "ok") {
              continue;
            } else if (status === "error") {
              console.error(
                `There was an error sending a notification: ${message}`
              );
              if (details && details.error) {
                // The error codes are listed in the Expo documentation:
                // https://docs.expo.io/push-notifications/sending-notifications/#individual-errors
                // You must handle the errors appropriately.
                console.error(`The error code is ${details.error}`);
              }
            }
          }
        } catch (error) {
          console.error(error);
        }
      }
    })();
  });

错误

$ firebase deploy --only functions

=== Deploying to 'appName'...

i  deploying functions
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i  functions: ensuring required API cloudbuild.googleapis.com is enabled...
i  functions: ensuring required API artifactregistry.googleapis.com is enabled...
+  functions: required API cloudbuild.googleapis.com is enabled
+  functions: required API cloudfunctions.googleapis.com is enabled
+  functions: required API artifactregistry.googleapis.com is enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (72.9 KB) for uploading
+  functions: functions folder uploaded successfully
i  functions: updating Node.js 16 function helloWorld(us-central1)...
i  functions: updating Node.js 16 function notifications(us-central1)...

Functions deploy had errors with the following functions:
        helloWorld(us-central1)
        notifications(us-central1)
i  functions: cleaning up build files...
Error: There was an error deploying functions:
- Error Failed to update function helloWorld in region us-central1
- Error Failed to update function notifications in region us-central1


$ firebase deploy --only functions

=== Deploying to 'appName'...

i  deploying functions
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i  functions: ensuring required API cloudbuild.googleapis.com is enabled...
i  functions: ensuring required API artifactregistry.googleapis.com is enabled...
+  functions: required API cloudfunctions.googleapis.com is enabled
+  functions: required API artifactregistry.googleapis.com is enabled
+  functions: required API cloudbuild.googleapis.com is enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (72.9 KB) for uploading
+  functions: functions folder uploaded successfully
i  functions: updating Node.js 16 function helloWorld(us-central1)...
i  functions: updating Node.js 16 function notifications(us-central1)...

Functions deploy had errors with the following functions:
        helloWorld(us-central1)
        notifications(us-central1)
i  functions: cleaning up build files...
Error: There was an error deploying functions:
- Error Failed to update function helloWorld in region us-central1
- Error Failed to update function notifications in region us-central1

我什至不确定此时该尝试什么。做了一些搜索,这似乎不是一个常见的问题,目前还没有找到任何解决方案。

如果我应该提供更多信息,请告诉我。

我可以 运行 $ firebase functions:log 或 ...-调试并共享输出。

如有任何帮助,我们将不胜感激。 谢谢!

包安装在项目的节点模块文件夹中,而不是函数文件夹的 node-modules。