LoginSignup
14
13

More than 3 years have passed since last update.

Nuxt+Firebase Cloud Messaging(FCM)でWebプッシュ通知を送る

Posted at

WebでもFCMが使えるようになったので、試してみたときの備忘録。
これでSafari以外には、通知が送れるようになる(´ω`)

使い方

構成は、@nuxtjs/pwaでPWA化している感じ。

コンソール側

Settingsでウェブプッシュ証明書を作成して、鍵ペアを取得する。

スクリーンショット_2020-05-24_17_06_33.png

これを、PUBLIC_VAPID_KEYという環境変数に設定しておく。

クライアント側

firebaseの初期化

~/plugins/firebase.tsというファイルを用意し、firebaseを初期化

// ~/plugins/firebase.ts
import * as firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
import "firebase/messaging";


if (!firebase.apps.length) {
  // まずは、firebaseの初期化
  firebase.initializeApp({
    apiKey: process.env.API_KEY,
    authDomain: process.env.AUTH_DOMAIN,
    databaseURL: process.env.DATABASE_URL,
    projectId: process.env.PROJECT_ID,
    storageBucket: process.env.STORAGE_BUCKET,
    messagingSenderId: process.env.MESSAGING_SENDER_ID,
    appId: process.env.APP_ID,
    measurementId: process.env.MEASUREMENT_ID
  });

  // Push通知をサポートしているかをチェック
  // サポートしていないと、firebase.messaging()を呼んだときに例外が発生
  const isSupported = firebase.messaging.isSupported();

  // コンソールで発行した、ウェブプッシュ証明書の鍵ペアを取得
  const publicVapidKey = process.env.PUBLIC_VAPID_KEY;
  if (!!publicVapidKey && process.client && !!isSupported) {
    // FCMの初期化。鍵ペアを設定する
    const messaging = firebase.messaging();
    messaging.usePublicVapidKey(publicVapidKey);

    // @nuxtjs/pwaが生成するsw.jsと、
    // 後で作成するFCM受信処理用のsw-firebase-messaging.jsを統合するための設定
    navigator.serviceWorker
      .register("/sw.js")
      .then(registration => messaging.useServiceWorker(registration))
      .catch(err => console.error(err));
  }
}

export default firebase;
トークンの取得

Push通知を送る際の宛先として、トークンを指定しないといけないので取得。
トークンは端末ごとに取得する必要があるので、注意が必要。
※PCとスマホだとそれぞれトークンが違う

import firebase from "~/plugins/firebase";

// トークンの取得
public async getToken(user: User) {
  const isSupported = firebase.messaging.isSupported();
  if (!isSupported) return;
  const token = await firebase.messaging().getToken();

  // firestoreにトークンを保存しておく処理(中身は略)
  await saveToken(user, token);
}

Firestoreなどへユーザごとにトークンを保存しておく。

firebase.messaging().getToken();を呼んだ際に、
通知の設定が「確認」だと、許可を求めるダイアログが表示される。

スクリーンショット 2020-05-24 16.30.23.png

これが許可されていないと、トークンも取得できない。

スクリーンショット 2020-05-24 16.30.35.png

メッセージを受け取ったときの処理

メッセージを受信したときに受け取る関数は2つあり、

  • フォアグラウンド(画面を見ている時) ... onMessage
  • バックグラウンド(画面を見ていない時) ... setBackgroundMessageHandler

・【参考】JavaScript クライアントでメッセージを受信する  |  Firebase

今回はバックグラウンドのときに通知を送りたいので、
setBackgroundMessageHandlerを設定していく。

こんな感じ。

ドキュメントを見ると、『firebase-messaging-sw.jsというファイル名で作成』と書かれているけど、
その名前にすると、自動で読み込まれてしまう。。

開発用と本番用で切り替えたいときなどもあるので、@nuxtjs/pwaが生成するsw.jsと統合できるように、
sw-firebase-messaging.jsという名前でファイルを作成しておく。

ファイル名を変更したので、上で書いている「firebaseの初期化」の部分で、
messaging.useServiceWorker(registration)を呼んでいる形。

// ~/static/sw-firebase-messaging.js
importScripts("https://www.gstatic.com/firebasejs/7.14.2/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/7.14.2/firebase-messaging.js");

// Firebaseの初期化
firebase.initializeApp({
  apiKey: "...",
  authDomain: "...",
  databaseURL: "...",
  projectId: "...",
  storageBucket: "...",
  messagingSenderId: "...",
  appId: "...",
  measurementId: "...",
});

// [START background_handler]
const isSupported = firebase.messaging.isSupported();
if (!!isSupported) {
  const messaging = firebase.messaging();
  // バックグラウンド時の処理
  messaging.setBackgroundMessageHandler(function(payload) {
   // 受け取ったFCMの内容を取得
    const notificationTitle = payload.notification.title;
    const notificationOptions = {
      body: payload.notification.body,
      icon: payload.notification.icon,
    };

    // 通知を作成する
    return self.registration.showNotification(notificationTitle, notificationOptions);
  });
}
// [END background_handler]
nuxt.config.tsでPWA関連の設定をする

作成したsw-firebase-messaging.jsを取り込む設定と、
@nuxtjs/pwaが生成するmanifest.jsonに、gcm_sender_idを追加する設定を追加

import { Configuration } from "@nuxt/types";

const config: Configuration = {
  // 略
  modules: [
    "@nuxtjs/pwa",
  ],

  workbox: {
    // sw-firebase-messaging.jsをimportするように追加
    importScripts: [
      "sw-firebase-messaging.js"
    ]
  },

  pwa: {
    manifest: {
      // manifest.jsonにgcm_sender_idを追加
      gcm_sender_id: process.env.MESSAGING_SENDER_ID || ""
    }
  },
};

export default config;

これでクライアント側はOK!

サーバ側: メッセージを送信する

メッセージの送信は、firebase-adminでできる。
アプリサーバーからの送信リクエストを作成する  |  Firebase

firestoreを利用しているので、Cloud Functionsのfirestoreトリガーを使い、
ドキュメントが追加されたら通知するようにしている例。

import * as functions from "firebase-functions";
import admin from "../common/firebaseAdmin"; // 初期化済みのfirebase-admin

export default functions
  .firestore.document("ドキュメントのパス")
  .onCreate(async (snap, context) => {
    // getTokenで保存しておいたトークンを取得(中身は略)
    const token = getToken();

    // 通知の送信
    const title = "通知するタイトル";
    const body = "通知する本文";
    const icon = "通知で表示するアイコン画像のURL"
    const link = "通知をタップしたときに開くURL"
    await admin.messaging().send({
        // 送信先の端末のトークン
        token: token,
        // 通知する内容
        notification: {
          title: title,
          body: body
        },
        // Web Push向けの通知内容
        webpush: {
          notification: {
            icon: icon
          },
          fcmOptions: {
            link: link
          }
        }
    });
  });

送信はこれだけ!

ほかの小ネタ

トークンを削除する

firebase.messaging().deleteToken();でトークンを無効化できる。

// トークンの削除
public async deleteToken(user: User) {
  const isSupported = firebase.messaging.isSupported();
  if (isSupported) {
    const token = await firebase.messaging().getToken();
    await firebase.messaging().deleteToken(token);
  }
}

フォアグラウンドで通知を受け取ったときになにかする

onMessageを使うと、通知を受け取ったときに呼び出してくれる。

firebase.messaging().onMessage(async (payload) => {
  // 受け取ったときの処理
});

トークンが変更されたときになにかする

onTokenRefreshを使うと、トークンが更新されたときに呼び出してくれる。

新しいトークンは再度getToken()を呼ばないといけない。

firebase.messaging().onTokenRefresh(async () => {
  // トークンが更新されたときの処理
});

通知の許可状態を確認する

通知の状態は、Notification.permissionで確認できるらしい。
Notification.permission - Web API | MDN

if (Notification.permission === "default") {
  // 確認(デフォルト)
} else if (Notification.permission === "granted") {
  // 許可
} else if (Notification.permission === "denied") {
  // 拒否
}

【PR】これをつかって、こんなのつくりました!

スクリーンショット 2020-05-24 12.44.28.png

こんな通知を受け取れます!
スクリーンショット_2020-05-24_13_34_17.png

1週間でWebサービスを作るイベント web1weekへの投稿作品です!
よかったら、遊んでみてください(´ω`)

■エアで投げ銭できるWebサービス「エア銭」
URL: https://air-money.netlify.app/

参考にしたサイトさま

14
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
13