bkr879
bkr879

Reputation: 2105

How to manage FCM push tokens

I would like to find a sustainable solution for storing FCM tokens used for push notifications. I am using React Native with Firebase.

The requirements are:

  1. User-based application
  2. Multiple devices per user supported
  3. No stale tokens stored at any time.

My current approach is:

Maintain a table user_devices with columns:

Maintain a uniqueness constraint on fcm_token and device_uuid.

Upon key events, including but not limited to:

send the following to the backend:

The backend then upserts a row with the above values. If the device uuid exists, that means, we overwrite the token (and, potentially, the user_id) for that device uuid.

The above approach is flawed because:

In other words, the table ends up storing many stale tokens and the application backend sends notifications to those stale tokens.

Additionally, the "Devices" frontend page (which shows the user their registered devices and reads from the above table) shows many duplicate devices that, really, represent the same device but have different device uuids.

One mitigation step could be to periodically send notifications to all tokens stored in the table with dry_run=true. Then, remove rows with tokens for which an error occurred. This is bad because it implies there is a period during which tokens are stale in the table.

I have scanned multiple resources online, including FCM documentation, but there is no mention on storing and maintaining those tokens in a real-world application. Are there any suggested approaches?

Upvotes: 3

Views: 1581

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 599956

The idiomatic approach is to remove a token when the Firebase Cloud Messaging API to send messages tells you that it is not valid.

For an example of how to do this, you can have a look at the Cloud Functions sample of sending notifications, which does the following:

  const response = await admin.messaging().sendToDevice(tokens, payload);
  // 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);

So each time you send one of more messages through FCM, you cull the invalid/outdated tokens from the database.

Upvotes: 1

Related Questions