tag:crieit.net,2005:https://crieit.net/tags/FirebaseCloudMessaging/feed 「FirebaseCloudMessaging」の記事 - Crieit Crieitでタグ「FirebaseCloudMessaging」に投稿された最近の記事 2020-05-24T17:18:35+09:00 https://crieit.net/tags/FirebaseCloudMessaging/feed tag:crieit.net,2005:PublicArticle/15909 2020-05-24T17:18:35+09:00 2020-05-24T17:18:35+09:00 https://crieit.net/posts/Nuxt-Firebase-Cloud-Messaging-FCM-Web Nuxt+Firebase Cloud Messaging(FCM)でWebプッシュ通知を送る <p>WebでもFCMが使えるようになったので、試してみたときの備忘録。<br /> これでSafari以外には、通知が送れるようになる(<em>´ω`</em>)</p> <h3 id="使い方"><a href="#%E4%BD%BF%E3%81%84%E6%96%B9">使い方</a></h3> <p>構成は、@nuxtjs/pwaでPWA化している感じ。</p> <h4 id="コンソール側"><a href="#%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E5%81%B4">コンソール側</a></h4> <p>Settingsでウェブプッシュ証明書を作成して、鍵ペアを取得する。</p> <p><img width="973" alt="スクリーンショット_2020-05-24_17_06_33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/d17f3a0e-e6df-73a7-d57b-a6ff36e7c79f.png"></p> <p>これを、PUBLIC_VAPID_KEYという環境変数に設定しておく。</p> <h4 id="クライアント側"><a href="#%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E5%81%B4">クライアント側</a></h4> <h5 id="firebaseの初期化"><a href="#firebase%E3%81%AE%E5%88%9D%E6%9C%9F%E5%8C%96">firebaseの初期化</a></h5> <p><code>~/plugins/firebase.ts</code>というファイルを用意し、firebaseを初期化</p> <pre><code class="typescript">// ~/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; </code></pre> <h5 id="トークンの取得"><a href="#%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E5%8F%96%E5%BE%97">トークンの取得</a></h5> <p>Push通知を送る際の宛先として、トークンを指定しないといけないので取得。<br /> トークンは端末ごとに取得する必要があるので、注意が必要。<br /> ※PCとスマホだとそれぞれトークンが違う</p> <pre><code class="typescript">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); } </code></pre> <p>Firestoreなどへユーザごとにトークンを保存しておく。</p> <p><code>firebase.messaging().getToken();</code>を呼んだ際に、<br /> 通知の設定が「確認」だと、許可を求めるダイアログが表示される。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/e9976414-8418-09c1-8846-25211a949776.png" alt="スクリーンショット 2020-05-24 16.30.23.png" /></p> <p>これが許可されていないと、トークンも取得できない。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/c21078c8-38d0-04c7-133a-b5402611443d.png" alt="スクリーンショット 2020-05-24 16.30.35.png" /></p> <h5 id="メッセージを受け取ったときの処理"><a href="#%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E5%8F%97%E3%81%91%E5%8F%96%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AE%E5%87%A6%E7%90%86">メッセージを受け取ったときの処理</a></h5> <p>メッセージを受信したときに受け取る関数は2つあり、</p> <ul> <li>フォアグラウンド(画面を見ている時) ... onMessage</li> <li>バックグラウンド(画面を見ていない時) ... setBackgroundMessageHandler</li> </ul> <p>・【参考】<a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/cloud-messaging/js/receive#handle_messages_when_your_web_app_is_in_the_background">JavaScript クライアントでメッセージを受信する  |  Firebase</a></p> <p>今回はバックグラウンドのときに通知を送りたいので、<br /> <code>setBackgroundMessageHandler</code>を設定していく。</p> <p>こんな感じ。</p> <p>ドキュメントを見ると、『<code>firebase-messaging-sw.js</code>というファイル名で作成』と書かれているけど、<br /> その名前にすると、自動で読み込まれてしまう。。</p> <p>開発用と本番用で切り替えたいときなどもあるので、@nuxtjs/pwaが生成するsw.jsと統合できるように、<br /> <code>sw-firebase-messaging.js</code>という名前でファイルを作成しておく。</p> <p>ファイル名を変更したので、上で書いている「firebaseの初期化」の部分で、<br /> <code>messaging.useServiceWorker(registration)</code>を呼んでいる形。</p> <pre><code class="javascript">// ~/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] </code></pre> <h5 id="nuxt.config.tsでPWA関連の設定をする"><a href="#nuxt.config.ts%E3%81%A7PWA%E9%96%A2%E9%80%A3%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%82%92%E3%81%99%E3%82%8B">nuxt.config.tsでPWA関連の設定をする</a></h5> <p>作成した<code>sw-firebase-messaging.js</code>を取り込む設定と、<br /> @nuxtjs/pwaが生成するmanifest.jsonに、gcm_sender_idを追加する設定を追加</p> <pre><code class="typescript">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; </code></pre> <p>これでクライアント側はOK!</p> <h4 id="サーバ側: メッセージを送信する"><a href="#%E3%82%B5%E3%83%BC%E3%83%90%E5%81%B4%3A+%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B">サーバ側: メッセージを送信する</a></h4> <p>メッセージの送信は、firebase-adminでできる。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/cloud-messaging/send-message?hl=ja">アプリサーバーからの送信リクエストを作成する  |  Firebase</a></p> <p>firestoreを利用しているので、Cloud Functionsのfirestoreトリガーを使い、<br /> ドキュメントが追加されたら通知するようにしている例。</p> <pre><code class="typescript">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 } } }); }); </code></pre> <p>送信はこれだけ!</p> <h3 id="ほかの小ネタ"><a href="#%E3%81%BB%E3%81%8B%E3%81%AE%E5%B0%8F%E3%83%8D%E3%82%BF">ほかの小ネタ</a></h3> <h4 id="トークンを削除する"><a href="#%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B">トークンを削除する</a></h4> <p><code>firebase.messaging().deleteToken();</code>でトークンを無効化できる。</p> <pre><code class="typescript">// トークンの削除 public async deleteToken(user: User) { const isSupported = firebase.messaging.isSupported(); if (isSupported) { const token = await firebase.messaging().getToken(); await firebase.messaging().deleteToken(token); } } </code></pre> <h4 id="フォアグラウンドで通知を受け取ったときになにかする"><a href="#%E3%83%95%E3%82%A9%E3%82%A2%E3%82%B0%E3%83%A9%E3%82%A6%E3%83%B3%E3%83%89%E3%81%A7%E9%80%9A%E7%9F%A5%E3%82%92%E5%8F%97%E3%81%91%E5%8F%96%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AB%E3%81%AA%E3%81%AB%E3%81%8B%E3%81%99%E3%82%8B">フォアグラウンドで通知を受け取ったときになにかする</a></h4> <p><code>onMessage</code>を使うと、通知を受け取ったときに呼び出してくれる。</p> <pre><code class="typescript">firebase.messaging().onMessage(async (payload) => { // 受け取ったときの処理 }); </code></pre> <h4 id="トークンが変更されたときになにかする"><a href="#%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%8C%E5%A4%89%E6%9B%B4%E3%81%95%E3%82%8C%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AB%E3%81%AA%E3%81%AB%E3%81%8B%E3%81%99%E3%82%8B">トークンが変更されたときになにかする</a></h4> <p><code>onTokenRefresh</code>を使うと、トークンが更新されたときに呼び出してくれる。<br /> 新しいトークンは再度<code>getToken()</code>を呼ばないといけない。</p> <pre><code class="typescript">firebase.messaging().onTokenRefresh(async () => { // トークンが更新されたときの処理 }); </code></pre> <h4 id="通知の許可状態を確認する"><a href="#%E9%80%9A%E7%9F%A5%E3%81%AE%E8%A8%B1%E5%8F%AF%E7%8A%B6%E6%85%8B%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B">通知の許可状態を確認する</a></h4> <p>通知の状態は、<code>Notification.permission</code>で確認できるらしい。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/API/notification/permission">Notification.permission - Web API | MDN</a></p> <pre><code class="typescript">if (Notification.permission === "default") { // 確認(デフォルト) } else if (Notification.permission === "granted") { // 許可 } else if (Notification.permission === "denied") { // 拒否 } </code></pre> <p>以上!!</p> <h3 id="【PR】これをつかって、こんなのつくりました!"><a href="#%E3%80%90PR%E3%80%91%E3%81%93%E3%82%8C%E3%82%92%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%A6%E3%80%81%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%82%8A%E3%81%BE%E3%81%97%E3%81%9F%EF%BC%81">【PR】これをつかって、こんなのつくりました!</a></h3> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/2f71c56a-0ab2-5910-f203-e1fca191ad69.png" alt="スクリーンショット 2020-05-24 12.44.28.png" /></p> <p>こんな通知を受け取れます!<br /> <img width="359" alt="スクリーンショット_2020-05-24_13_34_17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/1d4037bf-e662-a15a-4567-91f845ef5142.png"></p> <p>1週間でWebサービスを作るイベント <a href="https://crieit.net/boards/web1week-202005">web1week</a>への投稿作品です!<br /> よかったら、遊んでみてください(<em>´ω`</em>)</p> <p>■エアで投げ銭できるWebサービス「エア銭」<br /> URL: <a target="_blank" rel="nofollow noopener" href="https://air-money.netlify.app/">https://air-money.netlify.app/</a></p> <h1 id="参考にしたサイトさま"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88%E3%81%95%E3%81%BE">参考にしたサイトさま</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developers.cyberagent.co.jp/blog/archives/9662/">FRESH! における Web プッシュ通知機能 〜実装編〜 | CyberAgent Developers Blog</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/firebase/quickstart-js/blob/bcce38ebc1e5602560e2b76b20f19b7834b8279e/messaging/firebase-messaging-sw.js#L15-L37">quickstart-js/firebase-messaging-sw.js at bcce38ebc1e5602560e2b76b20f19b7834b8279e · firebase/quickstart-js</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/reference/js/firebase.messaging.Messaging#deletetoken">Messaging | JavaScript SDK  |  Firebase</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/cloud-messaging/js/send-multiple#%E3%83%88%E3%83%94%E3%83%83%E3%82%AF-http-post-%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88">複数のデバイスにメッセージを送信する  |  Firebase</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#WebpushConfig">REST Resource: projects.messages  |  Firebase</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/cloud-messaging/send-message">アプリサーバーからの送信リクエストを作成する  |  Firebase</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/cloud-messaging/js/first-message">バックグラウンド アプリにテスト メッセージを送信する  |  Firebase</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/cloud-messaging/js/client">JavaScript Firebase Cloud Messaging クライアント アプリを設定する</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/ryo_hisano/items/1171beca22d5a04ed802">Firebase Cloud Messagingで始めるWebプッシュ通知 - Qiita</a></li> </ul> きらぷか@積読ハウマッチ/SSSAPIなど