I have this Service Worker that receives notification well with Chrome,
but it's not receiving with firefox.
the Push listener is not fired at all in firefox (by debugging it),
PS: the service worker is successfully registered, but it's not receiving notification.
what's the problem with my code?
self.addEventListener('install', function (event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function (event) {
console.log('Activated', event);
});
self.addEventListener('push', function (event) {
event.waitUntil(
fetch('/path', {
credentials: 'include',
method: 'post',
})
.then(function (response) {
return response.json()
.then(function (data) {
return self.registration.showNotification(data.title, {
body: data.body,
icon: '/images/image.png',
});
});
})
.catch(function (error) {
console.error('wrong', error);
})
);
});
Based from this documentation, if you are using the Channel Messaging API to comunicate with the service worker, set up a new message channel (MessageChannel.MessageChannel()) and send port2 over to the service worker by calling Worker.postMessage() on the service worker, in order to open up the communication channel. You should also set up a listener to respond to messages sent back from the service worker.
Make sure that you followed these steps on how to set up the GCM properly. You can also check this related link: GCM Equivalent for Firefox
Hope this helps!
You will need to share your code in the client for registering for push notifications.
With that said, once you register for push notifications, you will receive a subscription with an endpoint. In Firefox that endpoint will never be a GCM url, but a push server provided by Mozilla:
navigator.serviceWorker.ready
.then((reg) => reg.pushManager.subscribe({ userVisibleOnly: true }))
.then((subscription) => {
const endpoint = subscription.endpoint;
// endpoint will have different server values when using this code in Chrome or Firefox.
Here are key notes to be considered:
Are you registering for push notifications correctly in firefox?
Check the url for the endpoint you will need to reach for performing the push notification, is a mozilla server one?
Setup breakpoints just after the push listener to verify that you receive the push.
Related
I am using service worker to check if a user is online or offline when a request is made. Here are some of the approaches I have taken:
In this method in service worker,
self.addEventListener("fetch", (event) => {
if (navigator.onLine){
}
})
navigator.onLine only works when you check/uncheck the offline checkbox in Inspect Element. But when I switch the device's internet on/off, it will always return true whether im offline or online.
And also from what i've seen in other answers, navigator.onLine will return true if you are connected to your local network even if your local network has no internet connection.
I have tried to ping a url in the self.addEventListener("fetch", {...}) method as shown here https://stackoverflow.com/a/24378589/6756827. This will bring an error in in the new XMLHttpRequest(); object.
I have tried to load an online resource (an image) in the self.addEventListener("fetch", {...}) method as shown here https://stackoverflow.com/a/29823818/6756827. The console shows an error for new Image();.
Because none of these approaches work, how do we check if a user is online or offline in service worker when a request is made ?
In the service worker you do not have access to the navigator object and thus no access to the online property or events.
Instead you know you are offline when a fetch throws an exception. The only time a fetch will throw an exception is when the device cannot connect to the Internet/Network.
self.addEventListener( "fetch", function ( event ) {
event.respondWith(
handleRequest( event )
.catch( err => {
//assume offline as everything else should be handled
return caches.match( doc_fallback, {
ignoreSearch: true
} );
} )
);
} );
For a more complex handling of the situation you can sync messages of online/offline state with the UI using the message API:
self.addEventListener( "message", event => {
//handle message here
}
I have my service worker installed like the following:
self.addEventListener('install', () => {
console.log('[sw]', 'Your ServiceWorker is installed');
});
self.addEventListener('push', ev => {
console.log('[sw]', 'pushed!!', ev.data.json());
const {title, msg, icon} = ev.data.json();
self.registration.showNotification(title, {
body: msg,
icon: icon,
});
});
I can use libraries like web-push, which actually fires an push event which is captured by service worker and shows a notification on demand (uses fcm for example in case of chrome). I just want to understand is there a way in which we can send a push notification to the user ourselves from our server, primarily on nodejs?
Can it be done?
I am new to PWA and have been testing my PWA project using firebase console database. When offline, I have code to save my post data in indexedDB when i submit my post data to saved later when there is WiFi(online). It did save the data in indexedDB when no WiFi found, but when i turn on my WiFi, it doesn't post my data in realtime. When i submit new post data when wifi on(online), background sync codes do post saved data from indexedDB with newly post data in real time. But i want my background sync codes to post automatically when WiFi is turned on(after offline).
Here is my service worker code for background sync:
self.addEventListener('sync', function(event) {
console.log('Background syncing...', event);
if (event.tag === 'sync-new-posts') {
console.log('Syncing new Posts...');
event.waitUntil(
readAllData('sync-posts') // function to read all saved data which had been saved when offline
.then(function(data) {
for (var dt of data) {
fetch('xxx some firebase post url xxx', { // fetching for sending saved data to firebase database
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
id: dt.id,
title: dt.title,
content: dt.content
})
})
.then(function(res) {
console.log('Sent data', res);
if (res.ok) {
res.json()
.then(function (resData) {
deleteItemFromData('sync-posts', resData .id); // function for deleting saved post data from indexedDB as we donot need after realtime post is saved when online.
});
}
})
.catch(function(err) {
console.log('Error while sending data', err);
});
}
})
);
}
});
I don't know what's go wrong. If anyone need more of my codes of my posting codes or serviceworker codes for more clarity, please do ask. Please help me with this as i am stuck in this.
What you can do is check weather the your app is online again or not using Online and offline events. This is a well documented JS API and is widely supported as well.
window.addEventListener('load', function() {
function updateOnlineStatus(event) {
if (navigator.onLine) {
// handle online status
// re-try api calls
console.log('device is now online');
} else {
// handle offline status
console.log('device is now offline');
}
}
window.addEventListener('online', updateOnlineStatus);
window.addEventListener('offline', updateOnlineStatus);
});
NOTE: It can only tell if the device is connected. BUT it CANNOT distinguish between a working internet connection or just a connection (Eg. WiFi hotspot without actual Internet connectivity).
So, I'd suggest you to do a fake API call in the navigator.onLine event just to check weather the actual internet is back or not (it can be a simple handshake as well) and once the is successful you can go on doing your regular API calls.
Check if update on reload is switched off and that you are fully offline. I had the same issue then it randomly started working when update on reload was turned off. I think its because it reinstalls the service worker each time you refresh the page so you're not in the state where the service worker is listening for the sync. Thats my theory to it anyway. Hope this helps...
I use pushwoosh for receive push notification in my web app.
every things working well and received push message in serviceworker listener but I want give push messge data from serviceworker and process it in another js class
main.js like this:
if ('serviceWorker' in navigator) {
console.log('Service Worker is supported');
navigator.serviceWorker.register('sw.js').then(function() {
return navigator.serviceWorker.ready;
}).then(function(reg) {
console.log('Service Worker is ready :^)', reg);
// TODO
}).catch(function(error) {
console.log('Service Worker error :^(', error);
});
}
// get push message data in main.js and process it
service worker like this :
self.addEventListener('push', function(event) {
console.log('Push message', event);
var title = 'Push message';
event.waitUntil(
self.registration.showNotification(title, {
'body': 'The Message',
'icon': 'images/icon.png'
}));
});
As I mentioned in a comment, this seems a slightly odd use-case for a service worker rather than a standard worker, but:
You can have your service worker send a message to all connected clients when it gets a message pushed to it.
This answer shows a complete example of a service worker talking to clients, but fundamentally:
The pages it manages listen for messages:
navigator.serviceWorker.addEventListener('message', event => {
// use `event.data`
});
The service worker sends to them like this:
self.clients.matchAll().then(all => all.forEach(client => {
client.postMessage(/*...message here...*/);
}));
Or with ES5 and earlier syntax (but I don't think any browser supporting service workers doesn't also support arrow functions):
Page listening:
navigator.serviceWorker.addEventListener('message', function(event) {
// use `event.data`
});
Worker sending:
self.clients.matchAll().then(function(all) {
all.forEach(function(client) {
client.postMessage(/*...message here...*/);
});
});
The message is being received and notification does pop up when I use an example text for notification.
I've set up an account with Google for push notifications on Chrome, but the response appears to be empty.
THE SERVICE WORKER
I have this on the service worker, but its empty.
self.addEventListener('push', function(event) {
//console.log('Received a push message', event);
console.log(event.data);
});
Then there's one other thing I've tried with Fetch, using the localhost url.
var url = 'http://localhost/notification/index.php?type=fg';
self.addEventListener('push', function(event) {
event.waitUntil(fetch(url).then(function(response) {
console.log(response);
return response.json();
}).then(function(data) {
console.log(data);
//'data' does't have the json from the url
})
)
});
Chrome doesn't support push payloads yet, so the first snippet will only work in Firefox (https://serviceworke.rs/push-payload.html).
Your second approach, instead, should work in any browser (https://serviceworke.rs/push-get-payload.html).