Search code examples
javascriptnext.jsfirebase-cloud-messagingtwilio

Twilio Conversations push notifications with Firebase Cloud Messaging


I'm attempting to set up push notifications using Twilio Conversations and Firebase Cloud Messaging on a Next.js 12 app. The documentation is written with the assumption of using Firebase 8 syntax, but I'm using Firebase 9 in this scenario. I've been struggling to get push notifications to work while the page is open. I have the service worker set up (per Firebase docs) but it doesn't seem to be recognizing that a new message is being received from Twilio in order to actually show the notification.

Docs I've followed:

What I've tried

On my backend, I pass the Push Credential SID when I construct a new ChatGrant:

const chatGrant = new ChatGrant({
  pushCredentialSid: process.env.TWILIO_PUSH_CREDENTIAL_SID,
  serviceSid: CONVERSATIONS_SID
});

In the frontend, I followed the Twilio documentation to set up Firebase:

init.ts

import { getMessaging, getToken, onMessage } from "firebase/messaging";
import { initializeApp } from "firebase/app";
import { Client } from "@twilio/conversations";

// Omitted
const firebaseConfig = {};

export function getPermission(client: Client) {
  const app = initializeApp(firebaseConfig);
  const messaging = getMessaging(app);
  getToken(messaging, { vapidKey:"KEY" })
    .then((data) => {
      console.log({ data });
      client.setPushRegistrationId("fcm", data).catch((error) => {
        console.error({ error });
      });
      onMessage(messaging, (payload) => {
        console.log({ payload });
        client.handlePushNotification(payload).catch((error) => {
          console.error(error);
          // test
        });
      });
    })
    .catch((error) => {
      console.error(error);
      // test
    });
}

I call getPermission from this file once when the conversation app loads.

  // chatClient is stored in a ref so it doesn't recalculate/refetch/reauthorize all the time
  const chatClient = useRef(null);
  // [Other code]
  chatClient.current = new ConversationClient(data.chatAccessToken);
  chatClient.current.on("connectionStateChanged", async (state) => {
    switch (state) {
      case "connected": {
        // Only get permission once the chat client is fully set up
        getPermission(chatClient.current);
        // ..........

And my service worker firebase-messaging-sw.js:

importScripts('https://www.gstatic.com/firebasejs/9.14.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/9.14.0/firebase-messaging-compat.js');

if (!firebase.apps.length) {
  firebase.initializeApp({
    // CONFIG GOES HERE
  });
}

const messaging = firebase.messaging();

//background notifications will be received here
messaging.onBackgroundMessage(function(payload) {
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here
  const notificationTitle = 'Background Message Title';
  const notificationOptions = {
    body: 'Background Message body.',
    icon: '/android-chrome-192x192.png'
  };

  self.registration.showNotification(notificationTitle, notificationOptions);
});

What's happening

  • In the service worker, messaging.onBackgroundMessage never appears to be invoked. I don't know where this issue is derived from - is Twilio not passing message info to Firebase? Or is Firebase not listening to when Twilio sends it the information? Has that changed from v8 to v9?
  • In init.ts, onMessage is never invoked. Same deal here, is Twilio not passing the right information to Firebase, or did I misconfigure something?

I'm not getting any console errors or warnings, and the network tab is not pointing out anything super helpful.


Solution

  • I got this to work by using the example code (from docs) and configuring my Next.js application to compile the TypeScript into JavaScript. This helped a lot: https://github.com/vercel/next.js/issues/33863#issuecomment-1140518693