webPush通知機能 完成!👏.これでブラウザ閉じても通知可能✌.

2024.11.12

Logging

おはようございます.金曜日の休みを使ってwebPush通知機能を追加しました、これでブラウザ閉じても通知されるようになります.Laravel側はお見せできませんがどういう技術を使用したか書いていきます.まずLaravelの拡張ライブラリを使用しました.

下記のリンクを参照しライブラリをインストールしてみてください.
https://laravel-notification-channels.com/webpush/#installation

インストール手順はリンク先に書いていますので、それを参照しその後フロント側を設定します.下記は作りかけのコードですが通知登録が可能でバックエンド側からスケジュールで通知を飛ばすことが出来ます.

フロント側はサービスワーカーのJSファイルとユーザー通知の許可行い、その情報をバックエンドに渡す処理ファイルが存在します.サービスワーカーJSコードはググれば書き方が出ているので検索してみてください.

公開するのは通知許可を行う方のファイルになります💁あとヒントとしてバックエンドも少し公開します.


const vapidPublicKey = import.meta.env.VITE_VAPID_PUBLIC_KEY;

async function setupPushNotifications() {
    if (Notification.permission === 'granted') {
        try {
            // サービスワーカーを登録
            await navigator.serviceWorker.register('/assets/js/npush-service-worker.js').then(async(registration) => {
                if ('serviceWorker' in navigator && 'PushManager' in window) {
                    try {
                            const subscription = await registration.pushManager.subscribe({
                                userVisibleOnly: true,
                                applicationServerKey: urlBase64ToUint8Array(vapidPublicKey),
                            });
            
                            const response = await fetch('/save-subscription', {
                                method: 'POST',
                                headers: {
                                    'Accept': 'application/json',
                                    'Content-Type': 'application/json',
                                    'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
                                },
                                body: JSON.stringify(subscription),
                            });
            
                            if (!response.ok) throw new Error('サブスクリプションの保存に失敗しました');
            
                            new Notification('ご登録', {
                                body: 'ご登録有難う御座います',
                            });
                        
                    } catch (error) {
                        console.error('Push subscription error:', error);
                    }
                } else if (result !== 'granted') {
                    console.log('通知の権限が拒否されました。');
                }       
            });
            console.log('サービスワーカーが正常に登録されました');
        } catch (error) {
            console.error('サービスワーカーの登録に失敗しました:', error);
        }
    }
}


function urlBase64ToUint8Array(base64String) {
    const padding = '='.repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);
    for (let i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
}

document.getElementById('enable-notifications').addEventListener('click', async () => {
    const permission = await Notification.requestPermission();
    if (permission === 'granted') {
        setupPushNotifications();
    } else {
        console.log('通知の権限が拒否されました。');
    }
});

これで通知の識別データが取得し登録が可能になります.登録されたデータを元に個別通知、全員に通知などが可能になります.なお、会員登録されたユーザーのみ通知が飛ぶシステムです.

        $endpoint = $request->endpoint;
        $token = $request->keys['auth'];
        $key = $request->keys['p256dh'];
        $user = $request->user();
        $user->updatePushSubscription($endpoint, $key, $token);

上記のデータがバックエンド側に保存されます.それを使用しユーザーにどのように送信すれば良いか?

use App\Notifications\Reserved;
$user = User::find(1);
$user->notify(new Reserved($reservation));

こんな感じだと思ってください.抜粋しているのであくまでもヒントです.あとはご自身で考えて対応してください.

明日へ続く

著者名  @taoka_toshiaki

※この記事は著者が40代前半に書いたものです.

Profile
高知県在住の@taoka_toshiakiです、記事を読んで頂きありがとうございます.
数十年前から息を吸うように日々記事を書いてます.たまに休んだりする日もありますがほぼ毎日投稿を心掛けています😅.
SNSも使っています、フォロー、いいね、シェア宜しくお願い致します🙇.
SNS::@taoka_toshiaki

OFUSEで応援を送る

タグ

addEventListener, assets, async, catch, document.getElementById, document.querySelector, headers, installation, keys, METHOD, padding, permission, rawData.charCodeAt, rawData.length, registration, repeat, replace, save-subscription, subscription, then,

サービスワーカー、フロント側のコード.スターウォーズみたいだね.

2024.11.09

Logging

おはようございます.サービスワーカーのプッシュ通知で使用するフロント側のコードの一部部分.このコードのregistration.pushManager等からググるとブラウザを閉じても通知できる方法などが記載しているサイトが見つかるかもしれません.尚、このサイトではこれ以上の情報を記載するつもりはないですが、後日、通知の機能の動画などを掲載するつもりではいます.

if ('serviceWorker' in navigator && 'PushManager' in window) {
    navigator.serviceWorker.ready.then(function(registration) {
        registration.pushManager.subscribe({
            userVisibleOnly: true,
            applicationServerKey: urlBase64ToUint8Array('VAPID_PUBLIC_KEY')
        }).then(function(subscription) {
            fetch('/api/save-subscription', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(subscription),
            });
        }).catch(function(error) {
            console.error('Push subscription error:', error);
        });
    });
}

function urlBase64ToUint8Array(base64String) {
    const padding = '='.repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);
    for (let i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
}

その時、どのようなライブラリーを使用したかや技術の一部を公開しようと思っています.ただ、全体のコードを全て公開するつもりは今の所はないです.理由は有料な情報でありこれで商売している人がいると思うので全ての技術情報を公開は控えるつもりです.

明日へ続く

著者名  @taoka_toshiaki

※この記事は著者が40代前半に書いたものです.

Profile
高知県在住の@taoka_toshiakiです、記事を読んで頂きありがとうございます.
数十年前から息を吸うように日々記事を書いてます.たまに休んだりする日もありますがほぼ毎日投稿を心掛けています😅.
SNSも使っています、フォロー、いいね、シェア宜しくお願い致します🙇.
SNS::@taoka_toshiaki

OFUSEで応援を送る

タグ

API, application, applicationServerKey, atob, catch, fetch, headers, METHOD, navigator, outputArray, padding, rawData.charCodeAt, rawData.length, registration, repeat, replace, save-subscription, subscription, then, userVisibleOnly,