NextjsでFCM使ってみた
2024-06-27
5 months ago
開発環境
- next 14.2.4
- firebase 10.12.2
前提
Nextjs、Firebaseのプロジェクトは作成済みを想定しています。
開発環境でフォアグラウンド、バックグランドで通知を受け取るところまでをゴールにしています。
また、firebaseConfigなど環境変数を入れるところは<your-xxx>としていますので、適宜ご自身の環境で設定してください。
本題
仕事でNextjsのプロジェクトにプッシュ通知を導入する予定があり、試しで簡単なサンプルを実装してみます。
1. firebase SDK導入
$ yarn add firebase
$ touch src/lib/firebase.ts
// Import the functions you need from the SDKs you need
import { initializeApp } from 'firebase/app';
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: '<your-api-key>',
authDomain: '<your-auth-domain>',
projectId: '<your-project-id>',
storageBucket: '<your-storage-bucket>',
messagingSenderId: '<your-messaging-sender-id>',
appId: '<your-app-id>',
};
// Initialize Firebase
const firebaseApp = initializeApp(firebaseConfig);
export default firebaseApp;
2. サービスワーカー設定
$ touch public/firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/8.8.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.8.0/firebase-messaging.js');
const firebaseConfig = {
apiKey: '<your-api-key>',
authDomain: '<your-auth-domain>',
projectId: '<your-project-id>',
storageBucket: '<your-storage-bucket>',
messagingSenderId: '<your-messaging-sender-id>',
appId: '<your-app-id>',
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.onBackgroundMessage((payload) => {
console.log(
'[firebase-messaging-sw.js] Received background message ',
payload,
);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: './your-logo.png',
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
3. ユーザーに通知を許可してもらうためのHooks
$ touch src/hooks/use-fcm-token.ts
import { useEffect, useState } from 'react';
import { getMessaging, getToken } from 'firebase/messaging';
import firebaseApp from '@/lib/firebase';
export const useFcmToken = () => {
const [token, setToken] = useState('');
const [notificationPermissionStatus, setNotificationPermissionStatus] =
useState('');
useEffect(() => {
const retrieveToken = async () => {
try {
if (typeof window !== 'undefined' && 'serviceWorker' in navigator) {
const messaging = getMessaging(firebaseApp);
// Retrieve the notification permission status
const permission = await Notification.requestPermission();
setNotificationPermissionStatus(permission);
// Check if permission is granted before retrieving the token
if (permission === 'granted') {
const currentToken = await getToken(messaging, {
vapidKey: '<your-vapid-key>',
});
if (currentToken) {
setToken(currentToken);
} else {
console.log(
'No registration token available. Request permission to generate one.',
);
}
}
}
} catch (error) {
console.log('An error occurred while retrieving token:', error);
}
};
retrieveToken();
}, []);
return { fcmToken: token, notificationPermissionStatus };
};
4. HooksをProviderに配置
$ touch src/providers/fcm.tsx
$ touch src/providers/app.tsx
import { type ReactNode, useEffect } from 'react';
import { getMessaging, onMessage } from 'firebase/messaging';
import { useFcmToken } from '@/hooks/use-fcm-token';
import firebaseApp from '@/lib/firebase';
type FCMProviderProps = {
children: ReactNode;
};
export const FCMProvider = ({ children }: FCMProviderProps) => {
const { fcmToken, notificationPermissionStatus } = useFcmToken();
// Use the token and status as needed
console.log({ fcmToken });
console.log({ notificationPermissionStatus });
useEffect(() => {
if (typeof window !== 'undefined' && 'serviceWorker' in navigator) {
const messaging = getMessaging(firebaseApp);
const unsubscribe = onMessage(messaging, (payload) => {
console.log('Foreground push notification received:', payload);
// Handle the received push notification while the app is in the foreground
// You can display a notification or update the UI based on the payload
});
return () => {
unsubscribe(); // Unsubscribe from the onMessage event
};
}
}, []);
return <>{children}</>;
};
'use client';
import React, { type ReactNode } from 'react';
import { FCMProvider } from './fcm';
type AppProviderProps = {
children: ReactNode;
};
export const AppProvider = ({ children }: AppProviderProps) => {
return <FCMProvider>{children}</FCMProvider>;
};
AppProviderをrootのlayout.tsxでimportして利用してください。
注意点
バックグラウンド通知の動作確認する上で、OSの通知設定(ブラウザの通知設定)を「オン」にする必要があります。
オフのままだとメッセージは受け取れているが、通知が届かない、という状態になるのでご注意ください。
さいごに
firebaseの説明を割愛しましたが、firebaseコンソールから適当にプロジェクトを作成し、Cloud Messagingにて「新しいキャンペーンの作成」でメッセージを送信することができます。