釣りとキャンプとコーヒーが好きなサラリーマンの趣味サイト。釣り場やキャンプ場とかの見てきたことや、Webの仕事で困ったことを記録していきます。

PWAのホームアイコンにFCMを使ってWebプッシュ通知を送信する方法。

PWAでwebpushを送る方法

PWAのホームアイコンを実装できれば、ユーザーがアクセスしやすくする面を獲得しつつ、キャッシュ機能でオフラインからのアクセスもできてユーザビリティがあがります。せっかくホームアイコンをインストールしてもらったら今度はプッシュ通知を送りたくなります。
ホームアイコン自体は簡単に実装できます。

WordPressならプラグインもあるので、ほんとに簡単に導入できます。


Webプッシュと呼ばれるこの機能、いざ実装しようと思うと一貫した実装方法の情報が少なくてなかなか苦戦しました。

一通りの学んだことをここにまとめておきたいと思います。

Webプッシュの仕組み

PWAを実装してみて、ホームアイコンの導入までは簡単にできる人は多いと思います。でもWebプッシュ通知となると急に難易度が上がるように感じます。それはWebプッシュに関して実装ベースまでまとまっている情報が少ないから。
なんとなく実装できそうな記事は多いんですけどね。
ここではこの記事通り組み込めばFCM経由でプッシュ通知を送る経験ができることを目標に書いていきたいと思います。

まずPUSH通知については以下の認識をしておきましょう。

Android/iOSアプリへのPUSH通知とWebプッシュ通知について

iOSアプリのプッシュ通知は Appleが提供しているPUSH通知サービスの「APNs(Apple Push Notification Service)」、Android アプリへのPUSH通知はGoogleが提供しているPUSH通知サービスの「FCM(Firebase Cloud Messaging)」を利用して実現されています。
一方でWebプッシュ通知はブラウザそのものにWebプッシュ通知を受け取れる機能を用意しておき、各ブラウザベンダーが提供しているPUSHサーバー(PUSHサービス)を経由してPUSH通知をブラウザに送っています。そして、そのブラウザに備わっているService Workerが、Webプッシュ通知をユーザーに表示します。

Webプッシュの通知機能は各ブラウザベンダーが提供しており、本来は各ブラウザ毎に実装する必要があったのですが、最近は Mozilla が採用していた VAPID (Voluntary Application Server Identification for Web Push) という仕組みを各ブラウザベンダーが採用したことでVAPIDに則って全ブラウザ共通のWebプッシュ通知機能が開発できるようになりました。
そしてGoogleがAndroidアプリ向けに提供しているFCMがこのVAPIDという仕組みに対応したことで、FCMを利用してVAPIDに対応してるブラウザに通知を送れるようになりました。
この点が、Webプッシュ機能を実装するときの情報を集めるときに、アプリPUSHの情報なのか、WebPUSHの情報なのかを混同しやすく原因になっています。

このあたりを理解する上では以下の記事がとてもわかりやすかったです。
参考記事:マッチングアプリ強者を体験できる PWA 開発で、Web プッシュ通知を理解しよう

FCM(Firebase Cloud Messaging)の準備

FCMを利用するための準備をします。
Firebaseでプロジェクトを作成する方法は先ほどの記事にわかりやすく書かれていますのでここでは割愛しますが、重要なのは「Settings」⇒「全般」⇒下部のマイアプリで「CDN」で表示されるスニペットの以下の部分です。
Firebase-snippet
ここをjsファイルにコピペしていくのですが、

<script src="https://www.gstatic.com/firebasejs/6.3.5/firebase-app.js"></script>

の部分はhtmlのheader何に書いておきましょう。

Service Workerの準備

PUSH通知は、PUSH通知を表示する仕組みと、PUSH通知を送信する2つの仕組みからできていると書きました。Service Workerはプッシュ通知を受け取り、表示する機能を担います。これを設定していきます。
ファイル名を「firebase-messaging-sw.js 」としてルートに設置します。そして下記のように記述してService Workerとして登録します。

<script>if ('serviceWorker' in navigator) {
   navigator.serviceWorker.register('/firebase-messaging-sw.js', 
    {scope:'/'}
   );}
</script>

そして、「firebase-messaging-sw.js」には下記のように記述しておきます。

// importScriptsはservice worker内から他のserviceworkerを読み込むときに使えます
importScripts("https://www.gstatic.com/firebasejs/6.3.4/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/6.3.4/firebase-messaging.js");

  // Your web app's Firebase configuration
  var firebaseConfig = {
    apiKey: "ウェブAPIキー",
    authDomain: "プロジェクトID.firebaseapp.com",
    databaseURL: "https://プロジェクトID.firebaseio.com",
    projectId: "プロジェクトID",
    storageBucket: "",
    messagingSenderId: "送信者ID",
    appId: "アプリID"
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
  const messaging = firebase.messaging();

/**
 * foreground時にメッセージを受け取ると、通知をする。通知の中身はtitleやoptionから設定できる。
 */
self.addEventListener("push", function(event) {
  const title = "Web担当者の休日";
  const options = {
    body: "新しい記事が公開されました。[push]",
    // 通知の右にでる画像
    icon:
      "",
      // 通知の左にでる画像
    badge: ""
  };

  event.waitUntil(self.registration.showNotification(title, options));
});


/**
 * background時の通知の扱い。ここではconsoleにメッセージを出力した上で、通知を出している。通知の中身はtitleやoptionから設定できる。
 */
messaging.setBackgroundMessageHandler(function(payload) {
  console.log(
    "[firebase-messaging-sw.js] Received background message ",
    payload
  );
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
    icon: payload.notification.icon
  };
  
  return self.registration.showNotification(
    notificationTitle,
    notificationOptions
  );
});

ここまで来ると、Chromeのデバッグツールで「Application」タブからプッシュ通知を表示することができます。
Chrome-push

FCM経由でWebプッシュ通知を送ってみる

さて、ここからが本番です。
FCM経由でWebプッシュ通知を送ります。その前に「app.js」というファイルを用意して以下のように記述します。

  // Your web app's Firebase configuration
  var firebaseConfig = {
    apiKey: "ウェブAPIキー",
    authDomain: "プロジェクトID.firebaseapp.com",
    databaseURL: "https://プロジェクトID.firebaseio.com",
    projectId: "プロジェクトID",
    storageBucket: "",
    messagingSenderId: "送信者ID",
    appId: "アプリID"
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
  const messaging = firebase.messaging();

//パーミッションチェックします。
  messaging.requestPermission()
  .then(function(){
    console.log('Have permission');
    return messaging.getToken();
  })
  .then(function(token){
  //あとでcurlコマンドにセットするデバイストークンを出力します
    console.log(token);
  })
  .catch(function(err){
    console.log('error Occuerd at getpermission');
     return messaging.getToken();
  })
 .then(function(token){
    console.log(token);
  });

  messaging.usePublicVapidKey(公開鍵);
  messaging.onMessage(function(payload){
    console.log('onMessage:',payload);
  });

「公開鍵」の部分はFirebaseの管理画面の「Settings」⇒「クラウドメッセージング」タブ⇒下部の「ウェブ設定」の「鍵ペア」に表示される値を適用します。
「messaging.requestPermission()」で通知の許可結果を取得しています。許可されるとデバイストークンを取得し、consoleに出力します。consoleに出力されるデバイストークンをプッシュ通知を送信する際の送信先として設定します。
htmlヘッダーには以下をセットしてきます。

<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-messaging.js"></script>
<script type="text/javascript" src="/app.js"></script>

このあたりの記述の仕方は以下の動画が参考になります。

ここまでの準備ができたらFCM経由でプッシュ通知を送りましょう。
windowsのcURLコマンドで下記のように通知を送ります。コマンドプロンプトを開いてcurlコマンドを打ち込んでみてください。
※表示上見やすくするためにネストしてますが、コマンド打ち込むときは、空白の削除など微調整してください。

curl 
 -X POST 
 -H "Authorization:key=サーバーキー" 
 -H "Content-Type:application/json" 
 -d "{\"notification\":
        {\"title\":\"Webtanpush-test\",
         \"body\":\"Webtan-pushtestu-body!\",
         \"icon\":\"アイコンへのパス\",
         \"click_action\":\"https://sumida-seabass.sakura.ne.jp\"
        },
      \"to\":\"デバイストークン"
     }" 
https://fcm.googleapis.com/fcm/send

サーバーキーはFirebaseコンソールの下記から取得します。
FCM-サーバーキーcurlコマンドで通知を送信する際、いろいろとエラーがでて苦労しました・・・。
各エラーの解消法をこちらにまとめています。

PWAの学習のために

PWAもいろんな実装方法があるので、自分に合った方法を調べるのはなかなか大変です。仕組み自体を正しく理解できると調べ方もわかってくるので、これからも作ってみながら勉強していきたいと思います。
英語ですが、たまたまちゃんと学習できるコンテンツがあったのでメモしておきます。
プログレッシブWebアプリ(PWA) – 完全ガイド