:::: MENU ::::

firebase-messaging.js を使ってハマったポイント3点

Pocket

Firebaseをいくらか使ってみて感じた、みんなもハマりそうなポイントをメモしておく。

setBackgroundMessageHandler が発火しない

ソースだけ見ていると、payloadにサーバーからプッシュで送りたいデータが入っていて、 showNotificationで表示させる前にカスタマイズできるところだなと思うのだが、
ここの仕様はちょっと複雑。

messaging.setBackgroundMessageHandler(function(payload) {
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here
  const notificationTitle = 'Background Message Title';
  const notificationOptions = {
    body: 'Background Message body.',
    icon: '/firebase-logo.png'
  };

  return self.registration.showNotification(notificationTitle,
      notificationOptions);
});

setBackgroundMessageHandler never fired · Issue #71 · firebase/quickstart-js
Githubのissueに発火しないぞと投稿があるように、
マニュアル通り使っていると setBackgroundMessageHandler が発火することはまずない。

# setBackgroundMessageHandler が発火しない
{
    "notification": {
        "title": "Background New Topic Title",
        "body": "Background New Topic body", 
        "click_action": "https://firebase.google.com/"
    },
    "data": {
        "id": "hogehoge",
        "age": 30
    },  
    "to": "[YOUR-REGISTRATION-ID]"
}

# setBackgroundMessageHandler が発火する
{
    "data": {
        "title": "Background New Topic Title",
        "body": "Background New Topic body", 
        "click_action": "https://firebase.google.com/", 
        "id": "hogehoge", 
        "age": 30
    }, 
    "to": "[YOUR-REGISTRATION-ID]"
}

notificationフィールドを使ってプッシュ通知で出したい要素を指定していると、setBackgroundMessageHandler を無視して通知が出る仕組みらしい。

解決策

notificationフィールドを使わずにすべてdataフィールドに入れておくと、setBackgroundMessageHandler が発火される!

Note: If you set notification fields in your HTTP or XMPP send request, those values take precedence over any values specified in the service worker.
(Receive Messages in a JavaScript Client  |  Firebase)

サーバーから送った値が優先されるのは知っていたが、
setBackgroundMessageHandler 自体が発火されないとは思わなかった。

自前の notificationclick の function が発火しない

notificationclose fired but notificationclick dose not fire · Issue #102 · firebase/quickstart-js
どうにもわからねぇとなってissueまで発行してしまったのだが、
firebase-messaging.js を読み返してたら自己解決した。

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

firebase.initializeApp({
  'messagingSenderId': 'xxxxx'
});
const messaging = firebase.messaging();

// not fire
self.addEventListener("notificationclick", function(event) {
  console.log('notification open');
  // log send to server
});

// fired
self.addEventListener("notificationclose", function(event) {
  console.log('notification close');
  // log send to server
});

初めはこんな感じで書いていたのだが、
notificationclone は反応するのに notificationclick が反応しない!!

firebase-messaging.js の中を見ると、
同じく notificatoinclick を呼んでいるがこちらは起動している。

      T.addEventListener("notificationclick", function (a) {
        return ga(b, a)
      }, !1);

addEventListener で add って言うくらいだから、
同じ element に対して同じ event type でいけるはずなのになぜ?

もうちょっと読み進めていくと怪しいメソッドを見つける。
(他にも notification.close で element を閉じてしまっているから後続の同elementを使う処理が動いていないのでは?と思ったが検討違いだった)

    ga = function (a, b) {
      if (b.notification && b.notification.data && b.notification.data.FCM_MSG) {
        b.stopImmediatePropagation();
        b.notification.close();

Event.stopImmediatePropagation() – Web APIs | MDN

stopImmediatePropagation どうやら多重実行防止のための関数らしい。
これ以降は addEventListener をしていても同じ element と event type のものは実行されない。

解決策

stopImmediatePropagation される前に addEventListener してしまえば、
先に実行されるので、これで自前の notificationclick が発火するようになった!

self.addEventListener("notificationclick", function(event) {
  console.log('notification open');
  var message = event.notification.data.FCM_MSG;
  console.log(message);
  // log send to server
});

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

firebase.initializeApp({
  'messagingSenderId': 'xxxxx'
});
const messaging = firebase.messaging();

日本語版のドキュメントは記述が古い

FCMの左メニューを見てもらえれば一目瞭然なのだが、
WebとFCMサーバーだけでもだいぶ違う。

そもそも大項目の時点でUnityとか日本語版はないし。
これのせいで1回古い仕様や非推奨の要素使って実装してしまった……

解決策

他の部分も情報が古い&情報自体がないことがあるので、
横着せずに英語版のドキュメントを読みましょう。

Pocket