読者です 読者をやめる 読者になる 読者になる

ボクココ

サービス開発を成功させるまでの歩み

Service Worker でスマホ Web 通知を実現する

JavaScript

ども、@kimihom です。

Service Worker といえば、最近出てきたバックグラウドでごにょごにょできて通知できるアレでしょ?程度にしか思ってなかったが、思いもよらず使う場面が出てきたのでメモ。本記事はおそらく Service Worker の中でも最もシンプルなサンプルコードの部類に入ると思う。

要件

Web Notification を スマホ Web でも実現したい。ページにとどまっている前提で、そのページで何かしらのイベントを発火した時に通知できればOK。ページにいない時にプッシュ通知を送るとかはしない。

Web Notification と スマホ Web

さて、普通の PC ブラウザでプッシュ通知を実現するのは、割と簡単にできる。以下のページから引用してきただけだが貼っておく。

Web Notifications を使用する - WebAPI | MDN

  if (Notification.permission === "granted") {
    var notification = new Notification("Hi there!");
  } else if (Notification.permission !== 'denied') {
    Notification.requestPermission(function (permission) {
      if (permission === "granted") {
        var notification = new Notification("Hi there!");
      }
    });
  }

PCのブラウザでは正しく通知が届くのだけども、これを スマホの Chrome とかで実行すると通知が出てこないんだよね。これを何とかしたいってのが今回の問題。

Service Worker を使う

Service Worker を使うことでスマホ Web でも同等のことが実現できた。

// 初期化
navigator.serviceWorker.register('/sw.js');

// 通知を送りたいタイミングで
navigator.serviceWorker.ready.then(function(registration) {
  registration.showNotification('CallConnect', {
    icon: '/icon.png',
    body: '通知です。'
  });
});

showNotification の細かいオプションはドキュメントを参照していただきたい。

んで/sw.js にはこんな感じの JavaScript をパブリックな場所に置いておこう。

self.onnotificationclick = function(event) {
  // close notification
  event.notification.close();

  event.waitUntil(
    clients.matchAll({includeUncontrolled: true}).then(function(clientList) {
      for (var i = 0; i < clientList.length; i++) {
        var client = clientList[i];
        if (client.url == "/" && 'focus' in client) {
          return client.focus(); 
        }
      }
    })
  );
};

これでスマホでの通知をタップしたら、その通知を消して通知を出したページに飛ぶことができる。(client.url == の部分は変える必要あるかも)

もちろんこれは通常の PC Web でも同じ動きになるので、統一したければ統一しても良いだろう。個人的には まだ出たばかり感の強い Service Worker の利用は最小限にとどめたいので スマホ Web だけ Service Worker を使って通知するようにした。

Debug Tips

一度 Service Worker にブラウザを登録すると、キャッシュ的な感じでページを更新しても 古い Service Worker の JavaScript のまんまだったりする。

その時は、chrome://serviceworker-internals/ を叩いて開き、そこにある該当の Service Worker を消すことで対応できる。

f:id:cevid_cpp:20160726212834p:plain

終わりに

Service Worker を動かすページにいる前提で通知を出すくらいだったら、手軽に Service Worker で スマホ通知を使えることをお分かりいただけたかと思う。

これがページにいないときにでもプッシュ通知を送るとかいう仕様にした途端に面倒なことが増えるので注意。てかページにいないのにプッシュ通知を送りまくるみたいなそんなページは滅びて欲しいので、それは知らなくていいことのように思える。

Service Worker をはじめとした最新の Web 技術は、モバイルアプリとモバイルウェブの垣根をなくしつつある。ゆくゆくは全ての モバイルアプリは HTML をベースとした Web アプリで置き換えられる日が来るのもそう遠くはないのかもしれない。