Help us understand the problem. What is going on with this article?

Firebase Cloud Messagingで始めるWebプッシュ通知

More than 1 year has passed since last update.

1)はじめに

スマホアプリと同じようなプッシュ通知の機能を、Webサイトに持たせる仕組みを使ってみましょう!みんな大好きmBaas、FirebaseのCloud Messaging(以下FCM)では、お手軽にWebプッシュ通知を実装することが可能です!なんと無料!太っ腹ですね!!:relaxed:

対応しているブラウザは【Desktop】Chrome / Firefox / Edge、【Mobile】Chrome / Firefoxとなっています。また、常時SSL必須となります。

今回のDEMOはこちら

2)FirebaseのJavaScriptタグを設置する

image.png
この画面の</>アイコンをクリックすると、下記のタグがポップアップするのでコピーしてHTML の一番下、他のスクリプトタグの前に貼り付けます。

index.html
<script src="https://www.gstatic.com/firebasejs/5.5.4/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: "<API_KEY>",
    authDomain: "<PROJECT_ID>.firebaseapp.com",
    databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
    projectId: "<PROJECT_ID>",
    storageBucket: "<BUCKET>.appspot.com",
    messagingSenderId: "<SENDER_ID>"
  };
  firebase.initializeApp(config);
</script>

3)manifest.jsonの作成

また、<head>内に下記タグを設置します。

index.html
<link rel="manifest" href="/manifest.json">

ウェブアプリ マニフェストファイル(manifest.json)を作成、ドキュメントルートに設置します。既にある場合は下記タグを追加します。
これは、FCMがこのアプリへのメッセージ送信を許可されていることを示しています(この値は固定値で変更不可)。

manifest.json
{
  "gcm_sender_id": "103953800507"
}

4)見た目を作る

今回はわかりやすいよう、下記のみを作成します。

通知の権限許可

トークン(インスタンスID)取得と画面への表示

cURLでプッシュ通知を送信

トークン削除

表画面側は下記のように、ボタンと入力フィールドを置いておきます。
image.png

index.html
<p>
    <input type="button" id="btnSubscribe" value="通知を許可する">
    <input type="button" id="btnUnSubscribe" value="トークン削除" style="display:none;">
</p>
<p><input type="text" value="YOUR-INCETANCE-ID-TOKEN" id="textInstanceIdToken" style="width:100%;box-sizing:border-box;"></p>
<div id="sendWebPushArea" style="display:none;">
    <p>下記をコピーしてこのタブを閉じ、別ブラウザで見てください</p>
    <input type="text" value="" id="sendWebPush" style="width:100%;box-sizing:border-box;">
</div>

5)処理の流れを理解する

main.jsを作成しこのページから参照します。

main.js
const btnSubscribe = document.getElementById('btnSubscribe');
const btnUnSubscribe = document.getElementById('btnUnSubscribe');
const textInstanceIdToken = document.getElementById('textInstanceIdToken');
const sendWebPushArea = document.getElementById('sendWebPushArea');
const sendWebPush = document.getElementById('sendWebPush');

// メッセージング オブジェクトの取得
const messaging = firebase.messaging();

// アプリにウェブ認証情報を設定する
messaging.usePublicVapidKey("<YOUR-PUBLIC-VAPID-KEY");

// 権限要求
function requestPermission() {
    // 通知を受信する権限を要求する
    messaging.requestPermission().then(function() {
        // 現在の登録トークンの取得
        messaging.getToken().then(function(token) {
            textInstanceIdToken.value = token;
            btnSubscribe.style.display = 'none';
            btnUnSubscribe.style.display = 'block';
            sendWebPushArea.style.display = 'block';
            sendWebPush.value = 'https://andus.heteml.jp/firebase_cloud_messaging/send.php?id=' + token;
        }).catch(function(err) {
            textInstanceIdToken.value = 'トークンの取得に失敗しました(' + err + ')。';
        });
    }).catch(function(err) {
        textInstanceIdToken.value = '通知の許可が得られませんでした(' + err + ')。';
    });
}

// トークン削除
function deleteToken() {
    // トークン取得
    messaging.getToken().then(function(currentToken) {
        // トークン削除
        messaging.deleteToken(currentToken).then(function() {
            textInstanceIdToken.value = 'トークンが削除されました';
            btnSubscribe.style.display = 'block';
            btnUnSubscribe.style.display = 'none';
            sendWebPushArea.style.display = 'none';
            sendWebPush.value = '';
        }).catch(function(err) {
            textInstanceIdToken.value = 'トークンの削除に失敗しました(' + err + ')。';
        });
    }).catch(function(err) {
        textInstanceIdToken.value = 'トークンの取得に失敗しました(' + err + ')。';
    });
}

// 初期化
window.onload = function() {
    // イベント登録
    btnSubscribe.onclick = requestPermission;
    btnUnSubscribe.onclick = deleteToken;
    // トークン取得
    messaging.getToken().then(function(currentToken) {
        if (currentToken) {
            // 本来ここでサーバにトークン送る処理
            //sendTokenToServer(currentToken);
            textInstanceIdToken.value = currentToken;
            btnSubscribe.style.display = 'none';
            btnUnSubscribe.style.display = 'block';
            sendWebPushArea.style.display = 'block';
            sendWebPush.value = 'https://andus.heteml.jp/firebase_cloud_messaging/send.php?id=' + currentToken;
        } else {
            // トークン無い場合
            textInstanceIdToken.value = '通知の許可をしていません。「通知を許可する」を押してください。';
        }
    }).catch(function(err) {
        textInstanceIdToken.value = 'トークンの取得に失敗しました(' + err + ')。';
    });
};

image.png
Firebase consoleのギアマークをクリック、「プロジェクトの設定」を選択、「クラウド メッセージング」を開きます。下の辺りの「ウェブ設定」「ウェブプッシュ証明書」の「鍵ペアを作成」をクリックします。
<YOUR-PUBLIC-VAPID-KEY>には生成した鍵ペアを設定します。
image.png

6)firebase-messaging-sw.jsの設置

ドキュメントルートにService Workerを設置します。
名前は「firebase-messaging-sw.js」で固定となります。

Service Workerとは?

バックグラウンド実行を可能にするJavaScriptで書かれたネットワークプロキシで、これによってモバイルでChromeを開いてない時にもプッシュ通知が可能となります。

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

firebase.initializeApp({
    'messagingSenderId': '<YOUR-MESSAGING-SENDER-ID>'
});

const messaging = firebase.messaging();

messaging.setBackgroundMessageHandler(function(payload) {
    const notificationTitle = payload.notification.title;
    const notificationOptions = {
        body: payload.notification.body,
        icon: payload.notification.icon
    };
    return self.registration.showNotification(notificationTitle, notificationOptions);
});

先程と同様にFirebase consoleにて「クラウド メッセージング」を開きます。
image.png
そして「プロジェクト認証情報」の「送信者ID」をコピーして<YOUR-MESSAGING-SENDER-ID>に貼り付け完了です。

7)PHPでcURLする

これで、得たトークンを使ってプッシュ通知を送ることが可能になりました。
image.png
DEMOページからsendすると通知が送られないため、別ブラウザで叩くことでテスト出来るようにしました。
※ 今回のプッシュ通知送信DEMOについては下記のトークンに$_GETメソッドで得た値を入れているだけです。

send.php
// 送るメッセージ
$json = '{
"notification":
{
    "title": "タイトルが入ります",
    "body": "本文が入ります",
    "icon": "https://●●●●●●●●●.com/message.png",
    "click_action": "https://●●●●●●●●●.com/"
},
"to": "<コピーしたトークン>"
}';

$ch = curl_init();

$headers = array(
    'Content-Type: application/json',
    'Authorization: key=<FCM_SERVER_KEY>'
);

curl_setopt_array($ch, array(
    CURLOPT_URL => 'https://fcm.googleapis.com/fcm/send',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => $json
));

$response = curl_exec($ch);

curl_close($ch);

<FCM_SERVER_KEY>には、先ほどの「プロジェクト認証情報」の「サーバーキー」を設定します。
そして、実際にcURLしてプッシュ通知を送信したのが下記キャプチャ(上がDesktop Chrome、下がAndroid端末)。
image.png
image.png

(まめちしき)デバッグ中にDesktop Chromeでサイトの通知をOFFにしたい時は、サイトの設定に行くよりはこっちが速い。
image.png

8)あとがき

実際にWebプッシュ通知サービスを独自に組み込もうと思ったら、ユーザーのログイン情報との紐付けや、個別のトークンの保存と管理が必須になってきます。サイトやブログの更新情報通知など、ユーザー属性を意識しなくても構わない場合にはトークンのみの保管でやって行けそうですね。
運用にあたり難しいのは、どんなタイミングでどの属性のユーザーに最適な情報を送れるか?ということでしょうね〜。

参考リンク

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした