LoginSignup
0
0

More than 3 years have passed since last update.

FireFox で service worker から見たブラウザの URL が正しくならない現象

Last updated at Posted at 2020-05-02

現象

webpush を実装して FireFox で動作確認をしていたところ、以下の現象に遭遇した。

  1. ページにアクセスする
  2. pushState で URL を変更する
  3. webpush を受信して client.url を見ると 1 の URL が参照される

Chrome では 2 の URL になってくれるのに。。。
今実装しているプロダクトでは以下の要件があるので URL を見て判定をしないといけないので困った。

  • 通知された URL をアクティブなページで表示していた場合は通知を表示しない
  • 通知をクリックした時に通知された URL が非アクティブなタブで開いていた場合は、それをアクティブにし、そうでない場合はタブを開く

環境

Mac 10.15 (Catalina)
FireFox 75.0

解決方法

client.url を見るのはやめた。

postMessage で URL を取得する方針に変更。
service worker からアプリに URL リクエストを postMessage して、
アプリ側ではそれを受けて location.href を postMessage で返信する。
実装は雰囲気こんな感じ。

sw.js

let resolveUrl = null;

const fetchUrl = client => {
  return Promise.race([
    new Promise(function (resolve) {
      resolveUrl = resolve;
      client.postMessage({ type: 'sw:requestUrl' });
    }),
    new Promise(function (resolve) {
      setTimeout(function () {
        resolve();
      }, 5000);
    })
  ]);
}

self.addEventListener('push', event => {
  if (!self.Notification || self.Notification.permission !== 'granted') {
    return;
  }

  const url = event.data.json().url;

  const notify = async () => {
    const clientList = await self.clients.matchAll({
      type: 'window'
    });

    for (let i = 0; i < clientList.length; i++) {
      const client = clientList[i]
      const clientUrl = await fetchUrl(client);
      if (
        client.visibilityState === 'visible'
        && clientUrl === url
      ) {
        return;
      }
    }
    self.registration.showNotification('通知', {});
  };
  event.waitUntil(notify());
});

self.onmessage = function(e) {
  if (e.data.type !== 'url') return;
  resolveUrl && resolveUrl(e.data.url);
};

アプリ側

const listener = (e: MessageEvent) => {
  if (e.origin !== location.origin || typeof e.data !== 'object') return;
  switch (e.data.type) {
    case 'sw:requestUrl':
      navigator.serviceWorker.controller?.postMessage({
        type: 'url',
        url: `${location.href}`
      });
      return;
    default:
      return;
  }
};
navigator.serviceWorker.addEventListener('message', listener);

これでなんとか解決。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0