web-dev-qa-db-ja.com

PushManagerサブスクリプションの取得中にエラーが発生しました-JavaScript

Service Workerを登録し、ユーザーに通知を許可するように求める次のコードがあります。 serviceWorkerRegistration.pushManager.getSubscription()によって返されるpromiseがnullであるプッシュ通知をユーザーが許可した後、エラーが発生します。ブラウザを閉じてこの関数呼び出しを再度強制すると、エラーなしで機能します。理由がわかりません。これが私のコードです:

_window.vapidPublicKey = new Uint8Array([4, 45, ...]); 
if (navigator.serviceWorker) {
  navigator.serviceWorker.register('/serviceworker.js')
  .then(function(reg) {
     console.log('Service worker change, registered the service worker');
  });
}
// Otherwise, no Push notifications :(
else {
  console.error('Service worker is not supported in this browser');
}

navigator.serviceWorker.ready.then((serviceWorkerRegistration) => {
  console.log("ready");
  serviceWorkerRegistration.pushManager
  .subscribe({
    userVisibleOnly: true,
    applicationServerKey: window.vapidPublicKey
  });
});



// application.js

// Let's check if the browser supports notifications
if (!("Notification" in window)) {
  console.error("This browser does not support notifications.");
}

// Let's check whether notification permissions have already been granted
else if (Notification.permission === "granted") {
  console.log("Permission to receive notifications has been granted");
}

// Otherwise, we need to ask the user for permission
else if (Notification.permission !== 'denied') {
  Notification.requestPermission(function (permission) {
    // If the user accepts, let's create a notification
    if (permission === "granted") {
      console.log("Permission to receive notifications has been granted");
      saveSubscriptionToDatabase();
    }
  });
}

function saveSubscriptionToDatabase(){

      navigator.serviceWorker.ready
      .then((serviceWorkerRegistration) => {
        console.log(serviceWorkerRegistration.pushManager.getSubscription());
        serviceWorkerRegistration.pushManager.getSubscription()
        .then((subscription) => {
          $.post("/users/save_subscription", { subscription: subscription.toJSON() });
        });
      });

}
_

エラー:

_Uncaught (in promise) TypeError: Cannot read property 'toJSON' of null
at serviceWorkerRegistration.pushManager.getSubscription.then
_

更新:

そこで、次のボタンを追加しました。

_ <input type="button" onclick="saveSubscriptionToDatabase();" value="test">
_

ボタンクリックから関数を呼び出す限り、JSとPOSTリクエストはすべて期待どおりに機能しますが、権限の状態を確認する条件から呼び出すと、以前と同じように失敗します。

更新2:

もう一度コードを書いてみましたが、別の角度からです。

_function registerServiceWorker() {
  return navigator.serviceWorker.register('serviceworker.js')
  .then(function(registration) {
    console.log('Service worker successfully registered.');
    return registration;
  })
  .catch(function(err) {
    console.error('Unable to register service worker.', err);
  });
}


function askPermission() {
  return new Promise(function(resolve, reject) {
    const permissionResult = Notification.requestPermission(function(result) {
      resolve(result);
    });

    if (permissionResult) {
      permissionResult.then(resolve, reject);
    }
  })
  .then(function(permissionResult) {
    if (permissionResult !== 'granted') {
      throw new Error('We weren\'t granted permission.');
    }
  });
}


function subscribeUserToPush() {
  return navigator.serviceWorker.register('serviceworker.js')
  .then(function(registration) {
    const subscribeOptions = {
      userVisibleOnly: true,
      applicationServerKey: new Uint8Array("key goes here")

    };

    return registration.pushManager.subscribe(subscribeOptions);
  })
  .then(function(pushSubscription) {
    console.log("never called");
    console.log('Received PushSubscription: ', JSON.stringify(pushSubscription));
    return pushSubscription;
  });
}

registerServiceWorker();
askPermission();
subscribeUserToPush();
_

subscribeUserToPush()があるconsole.log("never called");のコマンドチェーンの最後の部分は実行されず、エラーもありません。私はこれをChrome 67でテストしています。registration.pushManager.subscribe(subscribeOptions);が呼び出されることを確信しています。

7
Cannon Moyer

それで、何時間もさまざまなことを試した後、私はついに問題を理解しました、そしてそれは迷惑なほど単純でした。したがって、navigator.serviceWorker.register('serviceworker.js')を呼び出すたびに、ファイル名の前に/を付ける必要があります。 Service Workerは、/がなくても問題なく登録されますが、サブスクリプションの取得は失敗します。ドキュメントにある例には、/は含まれていません。

したがって、コードは次のようになっているはずです。

navigator.serviceWorker.register('/serviceworker.js')

多田今は動作します。

1
Cannon Moyer