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

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

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

[今回のDEMOはこちら]
(https://andus.heteml.jp/firebase_cloud_messaging/)

#２）FirebaseのJavaScriptタグを設置する
![image.png](https://qiita-image-store.s3.amazonaws.com/0/95865/3318086d-0ddc-1c35-aec6-7902755ee7f0.png)
この画面の&lt;/&gt;アイコンをクリックすると、下記のタグがポップアップするのでコピーしてHTML の一番下、他のスクリプトタグの前に貼り付けます。

```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>
```

#３）manifest.jsonの作成
また、&lt;head&gt;内に下記タグを設置します。

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

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

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

#４）見た目を作る
今回はわかりやすいよう、下記のみを作成します。

通知の権限許可
▼
トークン（インスタンスID）取得と画面への表示
▼
cURLでプッシュ通知を送信
▼
トークン削除

表画面側は下記のように、ボタンと入力フィールドを置いておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/95865/57e2f675-acf3-3487-77f1-4b0c6af2894d.png)

```html: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>
```

#５）処理の流れを理解する
main.jsを作成しこのページから参照します。

```javascript: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](https://qiita-image-store.s3.amazonaws.com/0/95865/c387b008-8a50-6c68-49ae-03abf6897a99.png)
Firebase consoleのギアマークをクリック、「プロジェクトの設定」を選択、「クラウド メッセージング」を開きます。下の辺りの「ウェブ設定」「ウェブプッシュ証明書」の「鍵ペアを作成」をクリックします。
&lt;YOUR-PUBLIC-VAPID-KEY&gt;には生成した鍵ペアを設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/95865/1d622c44-7335-e754-cb7b-ac3c6d306be3.png)

#６）firebase-messaging-sw.jsの設置
ドキュメントルートにService Workerを設置します。
名前は「firebase-messaging-sw.js」で固定となります。
##Service Workerとは？
バックグラウンド実行を可能にするJavaScriptで書かれたネットワークプロキシで、これによってモバイルでChromeを開いてない時にもプッシュ通知が可能となります。

```javascript: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](https://qiita-image-store.s3.amazonaws.com/0/95865/1cdb77fd-b228-59ce-7966-083cc9b91ab4.png)
そして「プロジェクト認証情報」の「送信者ID」をコピーして&lt;YOUR-MESSAGING-SENDER-ID&gt;に貼り付け完了です。

#７）PHPでcURLする
これで、得たトークンを使ってプッシュ通知を送ることが可能になりました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/95865/a3ec6bdd-5ec2-6e88-b7c5-99043d2c373b.png)
DEMOページからsendすると通知が送られないため、別ブラウザで叩くことでテスト出来るようにしました。
※ 今回のプッシュ通知送信DEMOについては下記のトークンに$_GETメソッドで得た値を入れているだけです。

```php: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);
```
&lt;FCM_SERVER_KEY&gt;には、先ほどの「プロジェクト認証情報」の「サーバーキー」を設定します。
そして、実際にcURLしてプッシュ通知を送信したのが下記キャプチャ（上がDesktop Chrome、下がAndroid端末）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/95865/1fdcc9f5-2d72-5a11-a2ac-68f6bbb3d46f.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/95865/59d4596f-21f7-89e3-e1de-a6b488940188.png)

（まめちしき）デバッグ中にDesktop Chromeでサイトの通知をOFFにしたい時は、サイトの設定に行くよりはこっちが速い。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/95865/979dc200-fb6a-ee88-96d3-e280e283f039.png)
#８）あとがき
実際にWebプッシュ通知サービスを独自に組み込もうと思ったら、ユーザーのログイン情報との紐付けや、個別のトークンの保存と管理が必須になってきます。サイトやブログの更新情報通知など、ユーザー属性を意識しなくても構わない場合にはトークンのみの保管でやって行けそうですね。
運用にあたり難しいのは、どんなタイミングでどの属性のユーザーに最適な情報を送れるか？ということでしょうね〜。

#参考リンク
- [JavaScript Firebase Cloud Messaging クライアント アプリを設定する  |  Firebase]
(https://firebase.google.com/docs/cloud-messaging/js/client?hl=ja)
- [quickstart-js/README.md at master · firebase/quickstart-js · GitHub]
(https://github.com/firebase/quickstart-js/blob/master/messaging/README.md)
- [Firebaseを使って簡単にプッシュ通知を行う方法 | フロントエンドBlog | ミツエーリンクス]
(https://www.mitsue.co.jp/knowledge/blog/frontend/201708/28_1146.html)
- [Can I use... Support tables for HTML5, CSS3, etc]
(https://caniuse.com/#feat=push-api)
- [FRESH! における Web プッシュ通知機能 〜実装編〜]
(https://developers.cyberagent.co.jp/blog/archives/9662/)
- [Webプッシュ通知にカスタムボタンが実装できるようになったので試してみた - Qiita]
(https://qiita.com/zaru/items/0d730e825a6b07db0d9b)
- [パーミッションの UX  |  Web Fundamentals  |  Google Developers]
(https://developers.google.com/web/fundamentals/push-notifications/permission-ux?hl=ja)