Web Notifications を使用する

Notifications API は、システムレベルでページ外部に表示される通知を Web ページやアプリから送ることを可能にします。これにより、アプリケーションがアイドルやバックグラウンドの状態であっても、アプリからユーザに情報を送信できます。この記事では、アプリで API を使用する方法の基礎を見ていきます。

註: この機能は Web Workers 内で利用可能です。

一般的にシステム通知とは、オペレーティングシステムの標準的な通知メカニズムを指します。一般的なデスクトップシステムやモバイルデバイスが、通知を行う方法の実例を思い出しましょう。

当然ながらシステム通知の仕組みはプラットフォームやブラウザによって異なりますが問題はなく、Notifications API はほとんどのシステム通知に対して十分な互換性を持つようになっています。

Web Notifications のもっともわかりやすい用途のひとつが、ユーザが別のアプリケーションを使用しているときでも新しいメッセージを受信したら通知が必要な、Web ベースのメールや IRC アプリケーションです。Slack など、実例がたくさんあります。

Web Notifications をどのように使用するかのアイデアを示すため、2 つの実例を掲載します:

.

許可の要求

アプリが通知を送信可能になる前に、ユーザはアプリがそれを行う権利を認めなければなりません。これは、API が Web ページの外部にあるものと対話しようとする際の一般的な要件です。ユーザは少なくとも 1 回はアプリケーションが通知を送ることを認めなければならず、これによりどのアプリやサイトが通知を表示してよいかをユーザが制御できます。

現在の許可状態を確認する

読み取り専用の Notification.permission プロパティの値を調べると、すでに許可を得ているかを確認できます。このプロパティは、3 種類の値のいずれかを持ちます:

default
ユーザはまだ許可を求められておらず、通知は表示されません。
granted
ユーザは以前に通知表示の許可を求められており、許可しました。
denied
ユーザは、通知の表示を明示的に拒否しました。

許可を得る

通知を表示する許可をまだ得ていない場合は、ユーザへ許可を求めるためにアプリケーションで Notification.requestPermission() メソッドが必要です。もっともシンプルな形式では Emogotchi のデモで使用しているように、以下のコードを含めます:

Notification.requestPermission();

このメソッドは任意でコールバック関数を指定でき、この関数は通知の表示を許可するかの要求に答えたときに呼び出されます (以下のサンプルで 2 番目の else ... if ブロックを参照)。一般的に通知を表示する許可は、アプリを最初に初期化するときでインスタンス化を行う前に要求します。完全な形にしたい場合は、以下のような構成を使用するとよいでしょう (To-do List Notifications をご覧ください):

コールバック版はオプションで、ユーザーが表示パーミッションの要求に答えた時に呼び出されるコールバック関数を受け入れます (下記の2つ目の else ... if ブロックにあるように) Commonly,

you'll ask for permission to display notifications when your app is first initialized, and before trying to instantiate any. If you wanted to be really thorough, you could use a construct like the following (see To-do List Notifications):

function notifyMe() {
  // ブラウザが通知をサポートしているか確認する
  if (!("Notification" in window)) {
    alert("このブラウザはシステム通知をサポートしていません");
  }

  // すでに通知の許可を得ているか確認する
  else 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!");
      }
    });
  }

  // 最後に、ユーザが通知を拒否した場合は、これ以上ユーザに 
  // 迷惑をかけてはいけないことを尊重すべきです。
}

注記: バージョン 37 より前の Chrome は、load イベントハンドラ内で Notification.requestPermission() を呼び出してはいけませんでした (issue 274284 をご覧ください)。

Firefox OS マニフェストでの許可設定

Notifications API は privilegedcertified ではありませんが、Firefox OS アプリに manifest.webapp ファイルを含める際に項目を含めてください:

"permissions": {
  "desktop-notification": {
    "description": "Needed for creating system notifications."
  }
},
"messages": [{"notification": "path/to/your/index.html"}]

注記: アプリケーションをインストールするとき、明示的に許可を求める必要はありませんが、通知を行うためには permissions および messages の項目が必要です。

通知を作成する

通知は簡単に作成でき、Notification コンストラクタを使用するだけです。このコンストラクタは通知で表示するタイトルや、アイコンあるいはテキスト本文といったオプションを受け取ると想定します。

例えば Emogotchi では、通知が必要になった際に呼び出す関数が 2 つあります。ひとつは通知を設定したいかに応じて呼び出すもの、もうひとつはランダムな内容を含む通知です:

function spawnNotification(theBody,theIcon,theTitle) {
  var options = {
      body: theBody,
      icon: theIcon
  }
  var n = new Notification(theTitle,options);
  setTimeout(n.close.bind(n), 5000); 
}

function randomNotification() {
  var randomQuote = quoteChooser();
  var options = {
      body: randomQuote,
      icon: 'img/sad_head.png',
  }

  var n = new Notification('Emogotchi says',options);
  setTimeout(n.close.bind(n), 5000); 
}

通知を閉じる

Firefox および Safari は、少し (4 秒程度) 経過したら自動的に通知を閉じます。またこれは、オペレーティングシステムレベルで行われます。一方 Chrome など、動作が異なるブラウザがあります。すべてのブラウザで確実に通知を閉じるには 4 秒後に通知を閉じるため、前出の関数の末尾に Notification.close 関数を収めた setTimeout() 関数を置きます。close() を通知に関連付けて呼び出すために bind() を使用していることに注意してください。

setTimeout(n.close.bind(n), 5000);

注記: "close" イベントを受け取るとき、ユーザが通知を閉じたことは保証されません。これは仕様書に準拠しており、以下のように記載されています: "When a notification is closed, either by the underlying notifications platform or by the user, the close steps for it must be run."

Notification イベント

Notifications API の仕様では、Notification のインスタンスで発生するイベントを 2 つ定義しています:

click
ユーザが通知をクリックしたときに発生します。
error
通知で問題が発生したときに発生します。通常、なんらかの理由で通知が表示されなかったためです。

これらのイベントは、onclick および onerror ハンドラを使用して追跡できます。NotificationEventTarget も継承していますので、addEventListener() メソッドも使用できます。

仕様書で定義されていたイベントはもう 2 つありますが、最近削除されました。しばらくの間ブラウザで動作しますが、廃止扱いされて使用できなくなるでしょう:

close
通知を閉じたときに発生します。
show
通知を表示したときに発生します。

既存の通知を置き換える

ユーザが短期間に多くの通知を受け取ることは、通常望ましくありません。例えばメッセンジャーアプリがメッセージを受け取るたびに通知を行って、それが大量になったらいかがでしょうか? 大量の通知によるスパム状態を避けるため、準備中の通知キューを変更して 1 つ以上の未表示通知を新た通知で置き換えることができます。

これを行うために、任意の新たな通知にタグを付加できます。すでに同じタグがついている通知がまだ表示されていない場合は、新しい通知が以前の通知を置き換えます。同じタグがついている通知がすでに表示されている場合は、前の通知を閉じて新しい通知を表示します。

タグの例

以下の基本的な HTML を想定します:

<button>Notify me!</button>

以下の方法で、複数の通知を扱うことが可能です:

window.addEventListener('load', function () {
  // 始めに、通知の許可を得ているかを確認しましょう
  // 得ていなければ、尋ねましょう
  if (window.Notification && Notification.permission !== "granted") {
    Notification.requestPermission(function (status) {
      if (Notification.permission !== status) {
        Notification.permission = status;
      }
    });
  }

  var button = document.getElementsByTagName('button')[0];

  button.addEventListener('click', function () {
    // 通知されることにユーザが同意している場合
    // 10 個の通知を送信してみましょう
    if (window.Notification && Notification.permission === "granted") {
      var i = 0;
      // 一部のブラウザ (Firefox を含む) は一定の期間内に大量の通知を行うとブロックするため、interval を使用します。
      var interval = window.setInterval(function () {
        // タグのおかげで、私たちは "Hi!9" の通知だけを見るでしょう 
        var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
        if (i++ == 9) {
          window.clearInterval(interval);
        }
      }, 200);
    }

    // 通知を受けたいか否かをユーザが告げていない場合
    // 注記: Chrome のために permission プロパティが設定されているかの確信が
    // 持てないため、値 "default" を確認するのは安全ではありません。
    else if (window.Notification && Notification.permission !== "denied") {
      Notification.requestPermission(function (status) {
        if (Notification.permission !== status) {
          Notification.permission = status;
        }

        // ユーザが認めている場合
        if (status === "granted") {
          var i = 0;
          // 一部のブラウザ (Firefox を含む) は一定の期間内に大量の通知を行うとブロックするため、interval を使用します。
          var interval = window.setInterval(function () {
            // タグのおかげで、私たちは "Hi!9" の通知だけを見るでしょう 
            var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
            if (i++ == 9) {
              window.clearInterval(interval);
            }
          }, 200);
        }

        // 認めていなければ、通常型の alert にフォールバックします
        else {
          alert("Hi!");
        }
      });
    }

    // ユーザが通知を拒否している場合
    else {
      // 通常型の alert にフォールバックできます
      alert("Hi!");
    }
  });
});

結果は以下のとおりです:

アプリの通知をクリックしたことの通知を受ける

アプリが生成した通知をユーザがクリックしたとき、アプリ側では状況に応じて 2 つの方法でクリックイベントの通知を受け取ることができます:

  1. 通知を作成してからユーザが通知をクリックするまでの間に、アプリが閉じられたりバックグラウンドに移されたりしていない場合は、click イベントを使用できます。
  2. それ以外の場合は、システムメッセージを使用します。

これらの扱い方の例については、こちらのコードスニペットをご覧ください。

仕様

仕様書 策定状況 コメント
Notifications API 現行の標準 Living standard

ブラウザ実装状況

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 5webkit[1]
22
4.0 moz[2]
22
未サポート 25 6[3]
icon 5webkit[1]
22
4.0 moz[2]
22
未サポート 25 未サポート
Available in workers ? 41.0 (41.0) ? ? ?
silent 43.0 未サポート 未サポート 未サポート 未サポート
noscreen, renotify, sound, sticky 未サポート 未サポート 未サポート 未サポート 未サポート
Feature Android Android Webview Firefox Mobile (Gecko) Firefox OS IE Mobile Opera Mobile Safari Mobile Chrome for Android
Basic support ?

(有)

4.0moz[2]
22
1.0.1moz[2]
1.2
未サポート ? 未サポート

(有)

icon ? (有) 4.0moz[2]
22
1.0.1moz[2]
1.2
未サポート ? 未サポート (有)
Available in workers ? ? 41.0 (41.0) ? ? ? ? ?
silent 未サポート 43.0 未サポート 未サポート 未サポート 未サポート 未サポート 43.0
noscreen, renotify, sound, sticky 未サポート 未サポート 未サポート 未サポート 未サポート 未サポート 未サポート 未サポート

[1] Chrome 22以前では、次の古いプレフィックス付きバージョンの仕様がサポートされており、新しい通知のインスタンスにはnavigator.webkitNotificationsオブジェクトを使用します。

Chrome 32以前では、Notification.permissionはサポートされていませんでした。

Chrome 42以前では、サービスワーカーの追加はサポートされていませんでした。

Chrome 49以降では、シークレットモードで通知はサポートされていません。

[2] Firefox 22 (Firefox OS <1.2)以前では、navigator.mozNotification オブジェクトを通じてcreateNotificationメソッドにより新しい通知を実行する必要があります。

Firefox 22 (Firefox OS <1.2)以前では、showメソッドを呼び出すと通知が表示され、 clickcloseイベントのみがサポートされています。

Nick Desaulniersは、Notification shimにおいて新旧両方の実装をカバーしています。

One particular Firefox OS issue is that you can pass a path to an icon to use in the notification, but if the app is packaged you cannot use a relative path like /my_icon.png. You also can't use window.location.origin + "/my_icon.png" because window.location.origin is null in packaged apps. The manifest origin field fixes this, but it is only available in Firefox OS 1.1+. A potential solution for supporting Firefox OS <1.1 is to pass an absolute URL to an externally hosted version of the icon. This is less than ideal as the notification is displayed immediately without the icon, then the icon is fetched, but it works on all versions of Firefox OS.

When using notifications  in a Firefox OS app, be sure to add the desktop-notification permission in your manifest file. Notifications can be used at any permission level, hosted or above: "permissions": { "desktop-notification": {} }

[3] Safari started to support notification with Safari 6, but only on Mac OSX 10.8+ (Mountain Lion).

関連情報

ドキュメントのタグと貢献者

 このページの貢献者: Uemmra3, yyss
 最終更新者: Uemmra3,