質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.03%

PWAのプッシュ通知時のトークン処理の稚拙な問題

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 541

Fujiman

score 15

状況

このサイトの「Push Notification編」を参考に
PWAでのプッシュ送信についてひと通りやりました。それに関しては問題なかったのですが
少し変えたいと変更を加えたときに、通知承認のデータを変数に受け取るという
問題が解決できず悩んでいます。
PWAとかNodeとかの以前の問題で、表題とほとんど関連性がないと思いますが・・・

プロジェクト概要

このプロジェクトの概要は、サイトのサービスワーカーに(service-worker.js)、
'push'イベントが発生すると既定の通知内容を表示するハンドラを設定しており、
main.jsではユーザがページにアクセスした際に、通知の承諾をすると
そのEndpoint、Author、Keyをページに表示します。
別途、push.jsというファイルにそれら表示情報を埋め込んで(npmの'web-push'を使ってます)
Nodeで実行しプッシュ通知の送信をするというものです

やろうとしていること

現状ではpush.jsの実行後に通知が表示されますが、これを、ユーザが承諾した時点でプッシュ通知を表示したいと思い、main.js内の、承諾時のデータを画面表示する処理の後にpush.jsの処理を追加しようとしました


main.js(変更前)
if ('serviceWorker' in navigator) {
    document.addEventListener('DOMContentLoaded', () => {
        let endpoint = document.querySelector('#subscription-endpoint');
        let key = document.querySelector('#subscription-public-key');
        let auth = document.querySelector('#subscription-auth');

        navigator.serviceWorker.register('./service-worker.js');
        navigator.serviceWorker.ready
                 .then((registration) => {
                     return registration.pushManager.subscribe({userVisibleOnly: true});
                 })
                 .then((subscription) => {
                     var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
                     key.value = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
                     var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
                     auth.value = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
                     endpoint.value = subscription.endpoint;
                     console.log(`GCM EndPoint is: ${subscription.endpoint}`);
                 })
                 .catch(console.error.bind(console));
    }, false);
}
push.js(変更前)
'use strict';
let push = require('web-push');
const GCM_API_KEY = '略';
push.setGCMAPIKey(GCM_API_KEY);
const data = {
    'endpoint': '略',
    'userAuth': '略',
    'userPublicKey': '略'
};

push.sendNotification(data.endpoint, {
    payload:       'service worker プッシュテスト',
    userAuth:      data.userAuth,
    userPublicKey: data.userPublicKey,
})
.then((result) => {
    console.log(result);
})
.catch((err) => {
    console.error('fail', err);
});

このmain.js内にpush.jsの内容を埋め込んでみたものが以下です。
画面表示に使っているデータを'web-push'に渡すオブジェクト”data”にセットしているだけです。
これをトランスパイルしてbundle.jsとし、main.jsのかわりにindex.htmlから呼びます
するとコンソールに後述のような'web-push'のエラーが出てしまいます。
ページにはAuth,Key,Endpointが表示されてはいますが。

App.js(main.jsにpush.jsを埋め込んだファイル)
'use strict';

let push = require('web-push');
const GCM_API_KEY = '略';
push.setGCMAPIKey(GCM_API_KEY);
let data = {
    'endpoint': '',
    'userAuth': '',
    'userPublicKey': '' 
};

if ('serviceWorker' in navigator) {
    document.addEventListener('DOMContentLoaded', () => {
        let endpoint = document.querySelector('#subscription-endpoint');
        let key = document.querySelector('#subscription-public-key');
        let auth = document.querySelector('#subscription-auth');

        navigator.serviceWorker.register('./service-worker.js');
        navigator.serviceWorker.ready
        .then((registration) => {
            return registration.pushManager.subscribe({userVisibleOnly: true});
        })
        .then((subscription) => {
            var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
            key.value = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
            var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
            auth.value = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
            endpoint.value = subscription.endpoint;
            data.endpoint = endpoint.value;
            data.userAuth = auth.value;
            data.userPublicKey = key.value;
        }).then(() => {
            push.sendNotification(data.endpoint, {
                payload:       'service worker プッシュテスト',
                userAuth:      data.userAuth,
                userPublicKey: data.userPublicKey,
            })
            .then((result) => {
                console.log(result);
            })
            .catch((err) => {
                console.error('fail', err);
            })
        }).catch(console.error.bind(console));
    }, false);
}
エラー内容
fail Error: "You must pass in a subscription with at least an endpoint."
    generateRequestDetails web-push-lib.js:89 sendNotification web-push-lib.js:289 [195]</</< App.js:36 
App.js:45:16
    [195]</</</< App.js:45 

少なくともエンドポイントは渡せという意味のエラーだと思うのですが、
なぜ渡せてないのかわからず悩んでいます。

もともとは画面表示しているデータをそのままコピペして実行するpush.jsなので
どうしてこれでまずいのかがわからす悩んでいます。
処理の流れが理解できていない気がします。
オブジェクト”data”の各プロパティーに値がセットされる前に、
そのプロパティーのチェック処理が走っているような感じなのですが

また、あわせて教えていただきたいのですが、後日のプッシュ通知にも使うために
このようにユーザから得た承認のトークンなどの管理は
一般的にはどうしているのでしょうか?
どんどんDataBaseなどに保存していっているのでしょうか?
逆にブラウザの通知設定で削除されたりして承認を得られなくなったら、
その保有していた承認のデータは削除するとかでアップデートし管理しているのでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる