firebase-js-sdk
firebase-js-sdk copied to clipboard
getToken throw error : DOMException: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker
Operating System
win 10
Browser Version
chrome 118.0.5993.71 (Official Build) (64-bit)
Firebase SDK Version
10.4.0
Firebase SDK Product:
Messaging
Describe your project's tooling
https://www.gstatic.com/firebasejs/10.4.0/firebase-app-compat.js https://www.gstatic.com/firebasejs/10.4.0/firebase-messaging-compat.js
Describe the problem
-
clear cookie
-
when open my web site for the first time, getToken throw the following error【NG】
-
when open my web site for the second time or refresh the tab, getToken works fine.
Steps and code to reproduce issue
return this.messaging.getToken({
vapidKey : this.vapidKey,
}).then((currentToken) => {
if (currentToken) {
console.log(currentToken);
return currentToken;
} else {
console.log('No Instance ID token available. Request permission to generate one.');
return null;
}
}).catch((err) => {
console.error(err);
});
having the same issue. it seems the service worker file firebase-messaging-sw.js
is installed when called getToken() for the first time, after refreshing and calling getToken again it then works..
I have similar issue as well. Reproducible in chrome 118 and safari. Seems to be critical, I haven't use the API before chrome 118, so can't say if it is a regression. Is there any insight here from the team @jbalidiong ?
So I took this temporary approach to the problem.
this.messaging
.getToken({
vapidKey : this.vapidKey,
}).catch((err) => {
// https://github.com/firebase/firebase-js-sdk/issues/7693
// 如果 getToken 时是还没注册 firebase-messaging-sw.js,就会报错如下,再次执行 getToken 就好了
const error = "AbortError: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker";
if (err.toString() === error) {
return this.messaging.getToken({
vapidKey : this.vapidKey,
});
} else {
throw err;
}
})
.then((currentToken) => {
if (currentToken) {
console.log(currentToken);
return currentToken;
} else {
console.log(
'No Instance ID token available. Request permission to generate one.'
);
return null;
}
})
.catch((err) => {
console.error(err);
});
I look forward to letting me know when this issue is completely fixed
Facing same issue with latest firebase 10.5.0. Please help with the fix.
@dpeese this solution worked for me
So I took this temporary approach to the problem.
this.messaging .getToken({ vapidKey : this.vapidKey, }).catch((err) => { // https://github.com/firebase/firebase-js-sdk/issues/7693 // 如果 getToken 时是还没注册 firebase-messaging-sw.js,就会报错如下,再次执行 getToken 就好了 const error = "AbortError: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker"; if (err.toString() === error) { return this.messaging.getToken({ vapidKey : this.vapidKey, }); } else { throw err; } }) .then((currentToken) => { if (currentToken) { console.log(currentToken); return currentToken; } else { console.log( 'No Instance ID token available. Request permission to generate one.' ); return null; } }) .catch((err) => { console.error(err); });
I look forward to letting me know when this issue is completely fixed
Running into the same issue. So is the recommended solution to just retry if it fails?
register Firebase service worker before getToken:
navigator.serviceWorker.register("/firebase-messaging-sw.js", { scope: "/firebase-cloud-messaging-push-scope" })
Hi bro. I am also facing a similar issue as you. And I fix it as follows.
const getOrRegisterServiceWorker = () => {
if ('serviceWorker' in navigator) {
return window.navigator.serviceWorker
.getRegistration('/firebase-cloud-messaging-push-scope')
.then((serviceWorker: TODO) => {
if (serviceWorker){
return serviceWorker;
}
return window.navigator.serviceWorker.register('/firebase-messaging-sw.js')
.then((serviceWorker: TODO)=>{
console.log("success registering SW");
}).catch((err)=>{
console.log("registering failed",err);
});
}
)}
throw new Error('The browser doesn`t support service worker.');
};
export const requestToken = async () => {
let currentToken = "";
try {
const serviceWorkerRegistration = await getOrRegisterServiceWorker();
currentToken = await getToken(messaging, {
vapidKey: key,
serviceWorkerRegistration
});
} catch (error) {
console.log("An error occurred while retrieving token. ", error);
}
return currentToken;
};
Solved by calling getToken()
twice.
The docs are confusing and outdated.
What should be the name of the service worker?
firebase-messaging-sw.js
(as shown here) or service-worker.js
(as shown here)
What version should I use for the Web namespaced API
?
8.10.1 or the latest one?
- Create a service worker
- Register it
- Then use serviceWorkerRegistration option to pass it to the getToken
https://github.com/benixal/FCM-Web-Notify-Example/blob/main/index.html#L35
https://www.youtube.com/watch?v=iz5arafmatc&t=6m12s
https://firebase.google.com/docs/reference/js/messaging_.gettokenoptions.md#gettokenoptionsserviceworkerregistration
I resolve it by waiting for activated state of ServiceWorker.
const getFBToken = (
m: Messaging,
serviceWorkerRegistration: ServiceWorkerRegistration
): Promise<string> | undefined => {
let sw: ServiceWorker | undefined;
if (serviceWorkerRegistration.installing) {
sw = serviceWorkerRegistration.installing;
} else if (serviceWorkerRegistration.waiting) {
sw = serviceWorkerRegistration.waiting;
} else if (serviceWorkerRegistration.active) {
sw = serviceWorkerRegistration.active;
}
if (sw) {
if (sw.state === 'activated') {
return getToken(m, {
vapidKey: import.meta.env.VITE_PUSH_PUBLIC_KEY,
serviceWorkerRegistration
});
}
const deferred = new Deferred<string>();
sw.addEventListener('statechange', async (e) => {
if ((e.target as ServiceWorker)?.state === 'activated') {
const token = await getToken(m, {
vapidKey: import.meta.env.VITE_PUSH_PUBLIC_KEY,
serviceWorkerRegistration
});
deferred.resolve(token);
}
});
return deferred.promise;
}
return undefined;
};
I resolved it like this
export async function generateToken({ subscribeTopic }: { subscribeTopic: (token: string) => void }) { try { const messaging = await getMessaging() // requesting permission using Notification API const permission = await Notification.requestPermission() if (!messaging) { return } if (permission !== 'granted') { return } if (!navigator.serviceWorker) { return } const serviceWorkerRegistration = await navigator.serviceWorker.ready if (serviceWorkerRegistration.active?.state === 'activated') { const token = await getToken(messaging, { vapidKey: VITE_FIREBASE_VAPID_KEY, serviceWorkerRegistration }) /* eslint-disable no-console */ console.log('[generateToken] token: ', token) subscribeTopic(token) } } catch (error) { console.log('[generateToken]:: error occur generateToken', error) } }
I tried registration, marking as ready, doing 3 ways, but nothing helped. Just try to get FCM Token multiple times and everything would be fine 💯
navigator.serviceWorker
.register("firebase-messaging-sw.js")
.then(() => navigator.serviceWorker.ready)
navigator.serviceWorker
.register("firebase-messaging-sw.js", { scope: '/' })
.then(() => navigator.serviceWorker.ready)
navigator.serviceWorker
.register("firebase-messaging-sw.js")
.then((registration) => registration.update())
.then(() => navigator.serviceWorker.ready)
registerDesktopDeviceForFirebaseMessaging() {
const messaging = getMessaging(this.app);
const webPushCertificateKeyPair = "ABC";
return this.tryGetFcmToken(messaging, webPushCertificateKeyPair, 3).catch((error) => {
console.error("Failed to get FCM token after retries:", error);
return Promise.reject();
});
}
private tryGetFcmToken(messaging: Messaging, vapidKey: string, retries: number) {
return new Promise((resolve, reject) => {
const attempt = () => {
getToken(messaging, { vapidKey })
.then((fcmToken) => {
return firstValueFrom(this.registerDesktopDeviceCommand(fcmToken))
.then(resolve)
.catch((error) => {
console.error("FcmTokenRegistrationFailed");
reject(error);
});
})
.catch((error) => {
if (retries > 0) {
retries--;
attempt();
} else {
reject(error);
}
});
};
attempt();
});
}
This worked for me:
const registration = await navigator.serviceWorker.register("sw.js")
// Wait for serviceWorker.ready
await navigator.serviceWorker.ready
const currentToken = await getToken(messaging, {
serviceWorkerRegistration: registration,
vapidKey: '...'
})
// Wait for serviceWorker.ready await navigator.serviceWorker.ready
This line is problematic if you have another service worker installed (as it should be the case for PWA apps), because it will not wait for the service you just registered, it will wait for the 1st one serving that page. I spent a few hours the other night trying to make sense of why my service worker was not responding and that was the culprit.
To fix you're going to have to wait on that SPECIFIC service worker. I know that there was a proposal to add that method to the spec, but I couldn't find it. https://github.com/w3c/ServiceWorker/issues/1278#issuecomment-433397392 So, this auxiliar function does the work:
function registerReady(swScript, options) {
return navigator.serviceWorker.register(swScript, options).then(reg => {
// If there is an active worker and nothing incoming, we are done.
var incomingSw = reg.installing || reg.waiting;
if (reg.active && !incomingSw) {
return Promise.resolve();
}
// If not, wait for the newest service worker to become activated.
return new Promise(fulfill => {
incomingSw.onstatechange = evt => {
if (evt.target.state === 'activated') {
incomingSw.onstatechange = null;
return fulfill();
}
};
});
})
}
And then use it:
registerReady("/firebase-messaging-sw.js", { scope: "/firebase-cloud-messaging-push-scope" }).then(function (registration) {
//get token
messaging.getToken({ vapidKey: '@Constants.FirebaseVapId', serviceWorkerRegistration: registration }).then(function (currentToken) {
if (currentToken) {
console.log('Generated new Firebase token: ' + currentToken);
}
})
.catch(function (err) {
console.log('Failed subscribing push notifications.', err);
});
});
currentToken = await getToken(messaging, {
vapidKey: key,
serviceWorkerRegistration
});
its work for me like this i add service worker registration as params to getToken function