前回の「特定の会員にリアルタイムでお知らせ」の記事は、ブラウザー内で表示するお知らせの話でした。つまり、ブラウザーを開いていないとお知らせは伝わりません。今回はブラウザーを開いてなくてもデスクトップ上でユーザーにお知らせします。

欲しい機能

簡単なデモとして、tinkerで以下のように、登録しているユーザー(ここでは太郎さん)にHello!というメッセージをNotificationを使用して送信します。メッセージを日本語にしたいのですが、tinkerでは英語しか使えません。

> use App\Notifications\Toast;
> $user = User::first();
> $user->notify(new Toast('Hello!'));

WindowsあるいはMacのデスクトップ上で右下にお知らせがスライドして登場します。

お知らせをクリックすると、指定したサイトに飛ばすことも可能です。

ソースコード

今回の機能を追加したソースコードは、前回の会員チャットをもとにして違うgitブランチ(chat-notification-desktop)としました。

レポジトリはこちらですが、すでにデモのソースコードをインストールしているなら、以下でスイッチできます。

$ git fetch
$ git checkout chat-notification-desktop

を実行してブランチをゲットできます。

chat-notificationとの差分は以下です。前回のブラウザーでのお知らせのToastのコンポーネントが廃止となり、後に説明するお知らせ許可のダイアログのコンポーネントが追加されています。

$ git diff chat-notification --name-status
M       resources/js/chat.js
D       resources/js/components/ChatToast.vue
A       resources/js/components/ConfirmModal.vue
M       resources/views/chat.blade.php

前回と同様に以下のコマンドを実行すると、ブラウザでテストが可能です。

$ npm run build
$ php artisan serve

お知らせ受信の許可

先のデモのように、ユーザーにお知らせするにはユーザーのデスクトップにおいて、ユーザーがブラウザーとサイトに許可(通知権限)を与える必要があります。サイトにアクセスするたびに毎回許可を問う必要はないです。1回許可(あるいは拒否)すればその後はその選択を尊重します。

しかし、この通知許可はユーザーの操作での起動が必要(ブラウザにより異なる)となるので、こちらが作成したボタンやダイアログの表示で許可を問い、その後さらにブラウザの方でポップアックしたダイアログでさらに許可を問うというやや面倒な手順となっています。

その部分のコードを見てみましょう。全体はこちらで見れます。

まず、通知許可がすでに選択されているかどうかチェックします。

...
createApp({
    setup () {
        const messages = ref([]);
        const modalVisible = ref(false);
...
        // 通知権限が既に決定されているかどうかを調べる
        if (Notification.permission === 'default') {
            modalVisible.value = true;
        }

Notificationはウェブの通知APIでたいていどのブラウザでも対応しています。このpermissionの値は、granted, denied, defaultの3つ文字列のどれかで、それぞれ、許可済み、拒否、未選択と意味です。未選択なら、以下のようなダイアログが表示されます。

このダイアログは、ConfirmDialogのコンポーネントでブレードでは以下のように使用されています。先ほどのmodalVisibleの値が更新されたゆえに、このダイアログが表示されます。

...
<confirm-modal
  :visible="modalVisible"
  v-on:confirmed="askPermission"
  question="お知らせを受け取りますか?">
</confirm-dialog>
...

このダイアログが表示されて、ユーザーが「はい」をクリックしたら、askPermissionの以下のコードが実行され、ダイアログを閉じて今度はブラウザの許可選択のポップアップを表示します。

...
        // 通知権限許可のモーダルのダイアログで「はい」をクリックしたら、今度はブラウザの通知許可を表示
        function askPermission() {
            modalVisible.value = false;

            Notification.requestPermission().then((permission) => {
                console.log(permission);
            });
        }
...

こちらがそのポップアップです。


ここでユーザーが許可して初めて、こちらのプログラムからユーザーにデスクトップのお知らせを送信することが可能となります。

お知らせの受信

お知らせを受け取り通知を作成する部分は前回と同様にLaravel Echoのnotificationを使用します。しかし、今度はウェブの通知APIで受け取ったメッセージを含めて通知を作成します。

....
       window.Echo.private('App.Models.User.' + window.userId)
            .notification((n) => {
                 // 通知権限が既に付与されているなら、通知を作成
                if (Notification.permission === 'granted') {
                    const notification = new Notification(
                        'ご連絡',
                        {
                            icon: 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Laravel.svg/180px-Laravel.svg.png',
                            body: n.message
                        }
                    );
                    notification.onclick = () => {
                        window.open('https://larajapan.com');
                    }
                }
            });
...

By khino