You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过Cloud Functions验证FCM Token的有效性?

Hey there! Let's tackle your two questions about FCM token validity checks in Cloud Functions—first, how to verify if a token is still valid, and second, how to validate tokens before sending notifications. I'll walk you through practical code examples and best practices below.

1. Checking if an FCM Token is Still Valid with Cloud Functions

FCM doesn't offer a dedicated API to check token validity directly, but we can leverage the fact that sending a minimal, low-priority test message will fail if the token is invalid or unregistered. Here's how to build a Cloud Function to do this:

Step-by-Step Implementation

  • First, make sure you've initialized the Firebase Admin SDK in your Cloud Functions project.
  • Create a callable function that accepts an FCM token, sends a silent test message, and checks for errors.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

exports.checkFCMTokenValidity = functions.https.onCall(async (data, context) => {
  const token = data.token;
  
  // Validate input
  if (!token) {
    throw new functions.https.HttpsError("invalid-argument", "FCM token is required");
  }

  try {
    // Send a silent, low-priority test message to avoid interrupting users
    const response = await admin.messaging().send({
      token: token,
      data: { "validation-test": "true" }, // Minimal payload
      android: { priority: "low" }, // Won't wake up the device
      apns: {
        payload: { aps: { contentAvailable: true } }, // Silent notification for iOS
        headers: { "apns-priority": "5" } // Low priority
      }
    });

    // If we get a message ID, the token is valid
    return {
      valid: true,
      messageId: response
    };
  } catch (error) {
    // Catch token-specific errors
    if (error.code === "messaging/invalid-registration-token" || 
        error.code === "messaging/registration-token-not-registered") {
      return {
        valid: false,
        reason: "Token is invalid or no longer registered"
      };
    }
    // Re-throw other errors as internal issues
    throw new functions.https.HttpsError("internal", "Failed to check token validity", error.message);
  }
});

Key Notes

  • Using low-priority/silent messages ensures users won't be bothered during validation.
  • The error codes messaging/invalid-registration-token and messaging/registration-token-not-registered are definitive signs that the token is no longer valid.
2. Validating Target Tokens Before Sending FCM Notifications

When sending notifications to multiple tokens, it's efficient to validate them in bulk during the send process. The sendMulticast method from the Admin SDK returns individual results for each token, letting you filter out invalid ones and update your database.

Bulk Validation & Notification Implementation

exports.sendNotificationsWithTokenValidation = functions.https.onCall(async (data, context) => {
  const targetTokens = data.tokens;
  const notificationContent = data.notification;

  // Validate input
  if (!targetTokens || !Array.isArray(targetTokens) || targetTokens.length === 0) {
    throw new functions.https.HttpsError("invalid-argument", "A non-empty array of tokens is required");
  }

  try {
    // Send multicast notification to all target tokens
    const response = await admin.messaging().sendMulticast({
      tokens: targetTokens,
      notification: notificationContent,
      // Optional: Use normal priority to balance delivery speed and user experience
      android: { priority: "normal" },
      apns: { headers: { "apns-priority": "5" } }
    });

    // Separate valid and invalid tokens from the results
    const invalidTokens = [];
    const successfulTokens = [];

    response.responses.forEach((result, index) => {
      if (!result.success) {
        // Check if failure is due to invalid token
        if (result.error.code === "messaging/invalid-registration-token" || 
            result.error.code === "messaging/registration-token-not-registered") {
          invalidTokens.push(targetTokens[index]);
        }
      } else {
        successfulTokens.push(targetTokens[index]);
      }
    });

    // Optional: Clean up invalid tokens from your database (example using Firestore)
    if (invalidTokens.length > 0) {
      const batch = admin.firestore().batch();
      // Assuming you have a "userTokens" collection storing tokens
      for (const token of invalidTokens) {
        const tokenDoc = await admin.firestore().collection("userTokens").where("token", "==", token).limit(1).get();
        if (!tokenDoc.empty) {
          batch.delete(tokenDoc.docs[0].ref);
        }
      }
      await batch.commit();
      functions.logger.info(`Removed ${invalidTokens.length} invalid tokens from database`);
    }

    // Return summary results
    return {
      successfulCount: response.successCount,
      failureCount: response.failureCount,
      invalidTokens: invalidTokens,
      successfulTokens: successfulTokens
    };
  } catch (error) {
    throw new functions.https.HttpsError("internal", "Failed to send notifications", error.message);
  }
});

Best Practices

  • Avoid redundant checks: Instead of validating tokens separately before every send, combine validation with the send process to save FCM quota.
  • Handle temporary errors: Some failures (like network issues) are temporary—you can add retry logic for those, but invalid tokens should be removed immediately.
  • Regular cleanup: Even with on-send validation, periodically scan your token database to remove stale entries (e.g., tokens older than 6 months).

内容的提问来源于stack exchange,提问作者Manatea Vagner

火山引擎 最新活动