diff --git a/src/shared/helpers/SubscriptionHelper.ts b/src/shared/helpers/SubscriptionHelper.ts index 6e864c56a..f772a7ae4 100755 --- a/src/shared/helpers/SubscriptionHelper.ts +++ b/src/shared/helpers/SubscriptionHelper.ts @@ -41,7 +41,7 @@ export default class SubscriptionHelper { await PermissionUtils.triggerNotificationPermissionChanged(); await EventHelper.checkAndTriggerSubscriptionChanged(); } catch (e) { - Log.info(e); + Log.error(e); } break; case WindowEnvironmentKind.OneSignalSubscriptionPopup: { diff --git a/src/shared/managers/ServiceWorkerManager.ts b/src/shared/managers/ServiceWorkerManager.ts index 373de242c..182da639b 100644 --- a/src/shared/managers/ServiceWorkerManager.ts +++ b/src/shared/managers/ServiceWorkerManager.ts @@ -174,6 +174,8 @@ export class ServiceWorkerManager { }); } + // Returns false if the OneSignal service worker can't be installed + // or is already installed and doesn't need updating. private async shouldInstallWorker(): Promise { // 1. Does the browser support ServiceWorkers? if (!Environment.supportsServiceWorkers()) return false; @@ -486,9 +488,11 @@ export class ServiceWorkerManager { * additional query parameters, but this must then stay consistent. */ - public async installWorker() { + public async installWorker(): Promise< + ServiceWorkerRegistration | undefined | null + > { if (!(await this.shouldInstallWorker())) { - return; + return this.getRegistration(); } Log.info('Installing worker...'); @@ -512,8 +516,12 @@ export class ServiceWorkerManager { Log.info( `[Service Worker Installation] Installing service worker ${workerHref} ${scope}.`, ); + + let registration: ServiceWorkerRegistration; try { - await navigator.serviceWorker.register(workerHref, { scope }); + registration = await navigator.serviceWorker.register(workerHref, { + scope, + }); } catch (error) { Log.error( `[Service Worker Installation] Installing service worker failed ${error}`, @@ -527,14 +535,21 @@ export class ServiceWorkerManager { throw error; } - await this.fallbackToUserModelBetaWorker(); + registration = await this.fallbackToUserModelBetaWorker(); } - Log.debug(`[Service Worker Installation] Service worker installed.`); + Log.debug( + `[Service Worker Installation] Service worker installed. Waiting for activation`, + ); + + await ServiceWorkerUtilHelper.waitUntilActive(registration); + + Log.debug(`[Service Worker Installation] Service worker active`); await this.establishServiceWorkerChannel(); + return registration; } - async fallbackToUserModelBetaWorker() { + async fallbackToUserModelBetaWorker(): Promise { const BETA_WORKER_NAME = 'OneSignalSDK.sw.js'; const configWithBetaWorkerName: ServiceWorkerManagerConfig = { @@ -557,7 +572,9 @@ export class ServiceWorkerManager { ); try { - await navigator.serviceWorker.register(workerHref, { scope }); + const registration = await navigator.serviceWorker.register(workerHref, { + scope, + }); const DEPRECATION_ERROR = ` [Service Worker Installation] Successfully installed v16 Beta Worker. @@ -568,6 +585,7 @@ export class ServiceWorkerManager { `; Log.error(DEPRECATION_ERROR); + return registration; } catch (error) { const response = await fetch(workerHref); if (response.status === 403 || response.status === 404) { diff --git a/src/shared/managers/SubscriptionManager.ts b/src/shared/managers/SubscriptionManager.ts index bb8c28016..118428b92 100644 --- a/src/shared/managers/SubscriptionManager.ts +++ b/src/shared/managers/SubscriptionManager.ts @@ -487,8 +487,10 @@ export class SubscriptionManager { } /* Now that permissions have been granted, install the service worker */ + let workerRegistration: ServiceWorkerRegistration | undefined | null; try { - await this.context.serviceWorkerManager.installWorker(); + workerRegistration = + await this.context.serviceWorkerManager.installWorker(); } catch (err) { if (err instanceof ServiceWorkerRegistrationError) { if (err.status === 403) { @@ -506,9 +508,6 @@ export class SubscriptionManager { throw err; } - Log.debug('[Subscription Manager] Getting OneSignal service Worker...'); - const workerRegistration = - await this.context.serviceWorkerManager.getRegistration(); if (!workerRegistration) { throw new Error('OneSignal service worker not found!'); } diff --git a/src/sw/helpers/ServiceWorkerUtilHelper.ts b/src/sw/helpers/ServiceWorkerUtilHelper.ts index 3ffe81b4a..2222086ce 100644 --- a/src/sw/helpers/ServiceWorkerUtilHelper.ts +++ b/src/sw/helpers/ServiceWorkerUtilHelper.ts @@ -33,4 +33,29 @@ export default class ServiceWorkerUtilHelper { } return availableWorker; } + + // Allows waiting for the service worker registration to become active. + // Some APIs, like registration.pushManager.subscribe, required it be active + // otherwise it throws. + static waitUntilActive( + registration: ServiceWorkerRegistration, + ): Promise { + return new Promise((resolve) => { + // IMPORTANT: checking non-active instances first, + // otherwise the 'statechange' event could be missed. + const inactiveWorker = registration.installing || registration.waiting; + if (inactiveWorker) { + inactiveWorker.addEventListener('statechange', () => { + Log.debug( + 'OneSignal Service Worker state changed:', + inactiveWorker.state, + ); + if (registration.active) { + resolve(); + } + }); + } + if (registration.active) resolve(); + }); + } }