Updating Web App User Interface when application is in background FCM - javascript

Am using FCM to handle notifications, it works fine up until when I need to update my UI from the firebase-messaging-sw.js when my web app is in the background.
My first question is: is it possible to update my web app UI in the background (When user is not focused on the web app) through a service worker
Secondly, if so, how? because I tried a couple of things and its not working, obviously am doing something wrong and when it does work, my web app is in the foreground. What am I doing wrong?
My codes are below.
my-firebase-service-sw.js
// [START initialize_firebase_in_sw]
// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here, other Firebase
libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/4.1.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.1.1/firebase-messaging.js');
// My Custom Service Worker Codes
var CACHE_NAME = 'assembly-v0.1.3.1';
var urlsToCache = [
'/',
'lib/vendors/bower_components/animate.css/animate.min.css',
'lib/vendors/bower_components/sweetalert/dist/sweetalert.css',
'lib/css/app_1.min.css',
'lib/css/app_2.min.css',
'lib/css/design.css'
];
var myserviceWorker;
var servicePort;
// Install Service Worker
self.addEventListener('install', function (event) {
console.log('installing...');
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function (cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
console.log('installed...');
});
// Service Worker Active
self.addEventListener('activate', function (event) {
console.log('activated!');
// here you can run cache management
var cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(function (cacheNames) {
return Promise.all(
cacheNames.map(function (cacheName) {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request)
.then(function (response) {
// Cache hit - return response
if (response) {
return response;
}
// IMPORTANT: Clone the request. A request is a stream and
// can only be consumed once. Since we are consuming this
// once by cache and once by the browser for fetch, we need
// to clone the response.
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function (response) {
// Check if we received a valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT: Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as the cache consuming the response, we need
// to clone it so we have two streams.
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function (cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
self.addEventListener('message', function (event) {
console.log("SW Received Message: " + event.data);
// servicePort = event;
event.ports[0].postMessage("SW Replying Test Testing 4567!");
});
myserviceWorker = self;
// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
'messagingSenderId': '393093818386'
});
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
// [END initialize_firebase_in_sw]
// If you would like to customize notifications that are received in the
// background (Web app is closed or not in browser focus) then you should
// implement this optional method.
// [START background_handler]
messaging.setBackgroundMessageHandler(function (payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
// send to client
console.log('Sending data to notification');
try {
myserviceWorker.clients.matchAll().then(function (clients) {
clients.forEach(function (client) {
console.log('sending to client ' + client);
client.postMessage({
"msg": "401",
"dta": payload.data
});
})
});
} catch (e) {
console.log(e);
}
const notificationTitle = payload.data.title;;
const notificationOptions = {
body: payload.data.body,
icon: payload.data.icon,
click_action: "value"
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
// [END background_handler]
In my main javascript file, which receives the payload. it receives it when the application is in the foreground. My major concern and problem is receiving payload when the application is in the background, all activities on foreground works just fine.

It is possible to update the UI even your website is opening but unfocused.
Just add enable option includeUncontrolled when you get all client list.
Example:
messaging.setBackgroundMessageHandler(function (payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
self.clients.matchAll({includeUncontrolled: true}).then(function (clients) {
console.log(clients);
//you can see your main window client in this list.
clients.forEach(function(client) {
client.postMessage('YOUR_MESSAGE_HERE');
})
})
});
In your main page, just add listener for message from service worker.
Ex:
navigator.serviceWorker.addEventListener('message', function (event) {
console.log('event listener', event);
});
See Clients.matchAll() for more details.

Related

Service Worker - how to know whether cache cleared?

I'm trying to implement a basic service worker to assure that users of my simple web app have the latest code. So when I update html, js, or css files I can increment the cachename in the service worker file and prompt users to refresh, clear their cache, and get the latest code.
Until now I've relied on hacky ways to update javascript files (including a parameter in the referring URL: /javascript-file.js?v=1).
The with the service worker code below seem unpredictable: sometimes small changes to JS or CSS are reflected after I increment the cachename (code below). Sometimes the changes are reflected without incrementing the cachename, which suggests the code is ALWAYS pulling from the network (wasting resources).
How can you troubleshoot which version of files the code is using and whether the service worker is using cached or network versions? Am I not understanding the basic model for using service workers to achieve this goal?
Any help appreciated.
serv-worker.js (in root):
console.log('Start serv-worker.js');
const cacheName = '3.2121';
var urlsToCache = [
'home.html',
'home-js.js',
'web-bg.js',
'css/main.css',
'css/edit-menus.css'
];
self.addEventListener('install', event => {
console.log('Install event...', urlsToCache);
event.waitUntil(
caches.open(cacheName)
.then(function(cache) {
console.log('Opened cache', cacheName);
return cache.addAll(urlsToCache);
})
);
});
// Network first.
self.addEventListener('fetch', (event) => {
// Check the cache first
// If it's not found, send the request to the network
// event.respondWith(
// caches.match(event.request).then(function (response) {
// return response || fetch(event.request).then(function (response) {
// return response;
// });
// })
// );
event.respondWith(async function() {
try {
console.log('aPull from network...', event.request);
return await fetch(event.request);
} catch (err) {
console.log('aPull from cache...', event.request);
return caches.match(event.request);
}
}());
});
self.addEventListener('message', function (event) {
console.log('ServiceWorker cache version: ', cacheName, event);
console.log('Received msg1: ', event.data);
if (event.data.action === 'skipWaiting') {
console.log('ccClearing cache: ', cacheName);
// caches.delete('1.9rt1'); // hardcode old one
// caches.delete(cacheName); // actually removes cached versions
caches.keys().then(function(names) {
for (let name of names)
caches.delete(name);
});
self.skipWaiting();
}
});
Code in web-bg.js, which home.html references:
function servWorker(){
let newWorker;
function showUpdateBar() {
console.log('Show the update mssgg...ddddd');
$('#flexModalHeader').html('AP just got better!');
$('#flexModalMsg').html("<p>AP just got better. Learn about <a href='https://11trees.com/support/release-notes-annotate-pro-web-editor/'>what changed</a>.<br><br>Hit Continue to refresh.</p>");
$('#flexModalBtn').html("<span id='updateAPbtn'>Continue</span>");
$('#flexModal').modal('show');
}
// The click event on the pop up notification
$(document).on('click', '#updateAPbtn', function (e) {
console.log('Clicked btn to refresh...');
newWorker.postMessage({ action: 'skipWaiting' });
});
if ('serviceWorker' in navigator) {
console.log('ServiceWORKER 1234');
navigator.serviceWorker.register(baseDomain + 'serv-worker.js').then(reg => {
console.log('In serviceWorker check...', reg);
reg.addEventListener('updatefound', () => {
console.log('A wild service worker has appeared in reg.installing!');
newWorker = reg.installing;
newWorker.addEventListener('statechange', () => {
// Has network.state changed?
console.log('SSState is now: ', newWorker.state);
switch (newWorker.state) {
case 'installed':
if (navigator.serviceWorker.controller) {
// new update available
console.log('Detected service worker update...show update...');
showUpdateBar();
}
// No update available
break;
}
});
});
});
let refreshing;
navigator.serviceWorker.addEventListener('controllerchange', function (e) {
console.log('a1111xxxListen for controllerchange...', e);''
if (refreshing) return;
console.log('Refresh the page...');
window.location.reload();
refreshing = true;
});
} // End serviceworker registration logic
return;
} // END serv-worker
You've commented out the section for /// Check the cache first and then below that the try/catch statement again pulls from the network and falls back to the cache.
Uncomment this section of code and see if you're loading from the cache first.
// event.respondWith(
// caches.match(event.request).then(function (response) {
// return response || fetch(event.request).then(function (response) {
// return response;
// });
// })
// );
Don't forget that even if you request from the network from the service worker the browser will still use it's own internal cache to serve data. How long the data stays in the browser's cache depends on the expiration headers being sent by the server.
When using expires, it's still a fairly common solution to do something like:
index.html - expires after an hour. Has script/css tags that call out file names with ?v=x.y.z
/resources - folder that holds js and css. This folder has a very long expiration time. But that long expiration is short circuited by changing the ?v=x.y.z in index.html
I've used the above successfully in Progressive Web Apps (PWAs). But it is a little painful when debugging. The best option here is to manually clear out the cache and service worker from Dev Tools \ Application, if you're in Chrome.

Workbox update cache on new version

I have implemented Workbox to generate my service worker using webpack.
This works pretty well - I can confirm that revision is updated in the generated service worker when running yarn run generate-sw (package.json: "generate-sw": "workbox inject:manifest").
The problem is - I have noticed my clients are not updating the cache after a new release.
Even days after updating the service worker my clients are still caching the old code and new code will only cache after several refreshes and/or unregister the service worker.
For each release the const CACHE_DYNAMIC_NAME = 'dynamic-v1.1.0' is updated.
How can I ensure that clients updates the cache immediately after a new release?
serviceWorker-base.js
importScripts('workbox-sw.prod.v2.1.3.js')
const CACHE_DYNAMIC_NAME = 'dynamic-v1.1.0'
const workboxSW = new self.WorkboxSW()
// Cache then network for fonts
workboxSW.router.registerRoute(
/.*(?:googleapis)\.com.*$/,
workboxSW.strategies.staleWhileRevalidate({
cacheName: 'google-font',
cacheExpiration: {
maxEntries: 1,
maxAgeSeconds: 60 * 60 * 24 * 28
}
})
)
// Cache then network for css
workboxSW.router.registerRoute(
'/dist/main.css',
workboxSW.strategies.staleWhileRevalidate({
cacheName: 'css'
})
)
// Cache then network for avatars
workboxSW.router.registerRoute(
'/img/avatars/:avatar-image',
workboxSW.strategies.staleWhileRevalidate({
cacheName: 'images-avatars'
})
)
// Cache then network for images
workboxSW.router.registerRoute(
'/img/:image',
workboxSW.strategies.staleWhileRevalidate({
cacheName: 'images'
})
)
// Cache then network for icons
workboxSW.router.registerRoute(
'/img/icons/:image',
workboxSW.strategies.staleWhileRevalidate({
cacheName: 'images-icons'
})
)
// Fallback page for html files
workboxSW.router.registerRoute(
(routeData)=>{
// routeData.url
return (routeData.event.request.headers.get('accept').includes('text/html'))
},
(args) => {
return caches.match(args.event.request)
.then((response) => {
if (response) {
return response
}else{
return fetch(args.event.request)
.then((res) => {
return caches.open(CACHE_DYNAMIC_NAME)
.then((cache) => {
cache.put(args.event.request.url, res.clone())
return res
})
})
.catch((err) => {
return caches.match('/offline.html')
.then((res) => { return res })
})
}
})
}
)
workboxSW.precache([])
// Own vanilla service worker code
self.addEventListener('notificationclick', function (event){
let notification = event.notification
let action = event.action
console.log(notification)
if (action === 'confirm') {
console.log('Confirm was chosen')
notification.close()
} else {
const urlToOpen = new URL(notification.data.url, self.location.origin).href;
const promiseChain = clients.matchAll({ type: 'window', includeUncontrolled: true })
.then((windowClients) => {
let matchingClient = null;
let matchingUrl = false;
for (let i=0; i < windowClients.length; i++){
const windowClient = windowClients[i];
if (windowClient.visibilityState === 'visible'){
matchingClient = windowClient;
matchingUrl = (windowClient.url === urlToOpen);
break;
}
}
if (matchingClient){
if(!matchingUrl){ matchingClient.navigate(urlToOpen); }
matchingClient.focus();
} else {
clients.openWindow(urlToOpen);
}
notification.close();
});
event.waitUntil(promiseChain);
}
})
self.addEventListener('notificationclose', (event) => {
// Great place to send back statistical data to figure out why user did not interact
console.log('Notification was closed', event)
})
self.addEventListener('push', function (event){
console.log('Push Notification received', event)
// Default values
const defaultData = {title: 'New!', content: 'Something new happened!', openUrl: '/'}
const data = (event.data) ? JSON.parse(event.data.text()) : defaultData
var options = {
body: data.content,
icon: '/images/icons/manifest-icon-512.png',
badge: '/images/icons/badge128.png',
data: {
url: data.openUrl
}
}
console.log('options', options)
event.waitUntil(
self.registration.showNotification(data.title, options)
)
})
Should I delete the cache manually or should Workbox do that for me?
caches.keys().then(cacheNames => {
cacheNames.forEach(cacheName => {
caches.delete(cacheName);
});
});
Kind regards /K
I think your problem is related to the fact that when you make an update to the app and deploy, new service worker gets installed, but not activated. Which explains the behaviour why this is happening.
The reason for this is registerRoute function also registers fetch listeners , but those fetch listeners won't be called until new service worker kicks in as activated. Also, the answer to your question: No, you don't need to remove the cache by yourself. Workbox takes care of those.
Let me know more details. When you deploy new code, and if users close all the tabs of your website and open a new one after that, does it start working after 2 refreshes? If so , that's how it should be working. I will update my answer after you provide more details.
I'd suggest you read the following: https://redfin.engineering/how-to-fix-the-refresh-button-when-using-service-workers-a8e27af6df68 and follow the 3rd approach.
One way to get WorkBox to update when you have the files locally, not on a CDN, is the following way:
In your serviceworker.js file add an event listener so that WorkBox skips waiting when there is an update, my code looks like this:
importScripts('Scripts/workbox/workbox-sw.js');
if (workbox) {
console.log('Workbox is loaded :)');
// Add a message listener to the waiting service worker
// instructing it to skip waiting on when updates are done.
addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
skipWaiting();
}
});
// Since I am using Local Workbox Files Instead of CDN I need to set the modulePathPrefix as follows
workbox.setConfig({ modulePathPrefix: 'Scripts/workbox/' });
// other workbox settings ...
}
In your client side page add an event listener for loads if service worker is in the navigator. As a note I am doing this in MVC so I put my code in the _Layout.cshtml so that it can update from any page on my website.
<script type="text/javascript">
if ('serviceWorker' in navigator) {
// Use the window load event to keep the page load performant
window.addEventListener('load', () => {
navigator.serviceWorker
// register WorkBox, our ServiceWorker.
.register("<PATH_TO_YOUR_SERVICE_WORKER/serviceworker.js"), { scope: '/<SOME_SCOPE>/' })
.then(function (registration) {
/**
* Whether WorkBox cached files are being updated.
* #type {boolean}
* */
let updating;
// Function handler for the ServiceWorker updates.
registration.onupdatefound = () => {
const serviceWorker = registration.installing;
if (serviceWorker == null) { // service worker is not available return.
return;
}
// Listen to the browser's service worker state changes
serviceWorker.onstatechange = () => {
// IF ServiceWorker has been installed
// AND we have a controller, meaning that the old chached files got deleted and new files cached
// AND ServiceWorkerRegistration is waiting
// THEN let ServieWorker know that it can skip waiting.
if (serviceWorker.state === 'installed' && navigator.serviceWorker.controller && registration && registration.waiting) {
updating = true;
// In my "~/serviceworker.js" file there is an event listener that got added to listen to the post message.
registration.waiting.postMessage({ type: 'SKIP_WAITING' });
}
// IF we had an update of the cache files and we are done activating the ServiceWorker service
// THEN let the user know that we updated the files and we are reloading the website.
if (updating && serviceWorker.state === 'activated') {
// I am using an alert as an example, in my code I use a custom dialog that has an overlay so that the user can't do anything besides clicking okay.
alert('The cached files have been updated, the browser will re-load.');
window.location.reload();
}
};
};
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}).catch(function (err) {
//registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
} else {
console.log('No service-worker on this browser');
}
</script>
Note: I used the browser's service worker to update my WorkBox cached files, also, I've only tested this in Chrome, I have not tried it in other browsers.

Service worker.js is not updating changes. Only if cache is cleared

This is my first PWA app with laravel. This code is working,it gets registered well, but if I do a change in the code, for example in the HTML, it is not getting update, and the console is not throwing errors, and I dont know why.
I'm using this code to call the service-worker.js
if ('serviceWorker' in navigator ) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}
And this is the code of the sw.js
var cache_name = 'SW_CACHE';
var urlsToCache = [
'/',
'/register'
];
self.addEventListener('install', function(event) {
event.waitUntil(precache());
});
addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function(response) {
// Check if we received a valid response
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
var responseToCache = response.clone();
caches.open(cache_name)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
var fromCache = function (request) {
return caches.open(cache_name).then(function (cache) {
cache.match(request).then(function (matching) {
return matching || Promise.resolve('no-match');
});
});
}
var update = function (request) {
return caches.open(cache_name).then(function (cache) {
return fetch(request).then(function (response) {
return cache.put(request, response);
});
});
}
var precache = function() {
return caches.open(cache_name).then(function (cache) {
return cache.addAll(urlsToCache);
});
}
Y also used skipWaiting(); method inner Install method, but it crash my app and have to unload the sw from chrome://serviceworker-internals/
This is what service worker lifecycle suppose to work: a new service worker won't take place, unless:
The window or tabs controlled by the older service worker are closed and reopened
'Update on reload' option is checked in Chrome devtools
Here is an official tutorial explained it well: The Service Worker Lifecycle
Service worker will always use the existing worker. Two thinks you can do is in chrome there is an option to set update on load
Goto InspectorWindow (f12) -> application -> and check update on reload.
if you want immediate update you can choose the network first cache approach. which will take the latest from server always and use the cache only in offline mode. see the link for more information
How API is getting cached effectively, Using Service worker in Angular 5 using Angular CLI

navigator.serviceWorker.controller is null until page refresh

I work with angularjs and use service worker to receive push notification.
but navigator.serviceWorker.controller is null until page refresh,and I don't know how to do to solve this problem
some code of serviceworker :
self.addEventListener('push', pwServiceWorker.pushReceived);
self.addEventListener('notificationclick', pwServiceWorker.notificationClicked);
// refresh caches
self.addEventListener('activate', function (event)
{
event.waitUntil(
caches.keys().then(function (cacheNames)
{
return Promise.all(
cacheNames.map(function (cacheName)
{
return caches.delete(cacheName);
})
);
})
);
});
and send message to the client in serviceworker when push received :
self.clients.matchAll().then(function(all) {
console.log(all);
all.forEach(function(client) {
client.postMessage(data);
});
});
in mainController.js give message like this :
if (!navigator.serviceWorker || !navigator.serviceWorker.register) {
console.log("This browser doesn't support service workers");
return;
}
// Listen to messages from service workers.
navigator.serviceWorker.addEventListener('message', function(event) {
console.log("Got reply from service worker: " + event.data);
});
// Are we being controlled?
if (navigator.serviceWorker.controller) {
// Yes, send our controller a message.
console.log("Sending 'hi' to controller");
navigator.serviceWorker.controller.postMessage("hi");
} else {
// No, register a service worker to control pages like us.
// Note that it won't control this instance of this page, it only takes effect
// for pages in its scope loaded *after* it's installed.
navigator.serviceWorker.register("service-worker.js")
.then(function(registration) {
console.log("Service worker registered, scope: " + registration.scope);
console.log("Refresh the page to talk to it.");
// If we want to, we might do `location.reload();` so that we'd be controlled by it
})
.catch(function(error) {
console.log("Service worker registration failed: " + error.message);
});
}
This is expected behavior. To take control over all open pages without waiting for refresh/reopen, you have to add these commands to your Service Worker:
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting()); // Activate worker immediately
});
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim()); // Become available to all pages
});
You can read more about them in skipWaiting() docs and clients.claim() docs.
Make sure the scope of your service worker includes the url in question.

Using chrome push notifications mainfest.json in meteor project

I am following a guide on how to implement the chrome push notification and I am trying to implement it in a Meteor app as a package.
Because I am unable to include the manifest.json I am getting "Registration failed - no sender id provided" or "Registration failed - permission denied". So how can I include this file in my project?
The manifest.json looks like this:
{
"permissions": [ "gcm" ],
"name": "push",
"short_name": "push notification",
"display": "standalone",
"gcm_sender_id": "0000000000000"
}
I have tried including it with the package.js like:
api.addAssets('manifest.json', 'client');
And also put the required variables (gcm_sender_id) in settings.json and starting meteor with meteor --settings settings.json but nothing works.
My service worker registration starts with calling Cpn.serviceWorkerRegistration:
Cpn = {};
Cpn.serviceWorkerRegistration = function () {
console.log("serviceWorkerRegistration called");
subscribe();
console.log(navigator);
// Check that service workers are supported, if so, progressively
// enhance and add push messaging support, otherwise continue without it.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(initialiseState);
} else {
console.warn('Service workers aren\'t supported in this browser.');
}
}
// Once the service worker is registered set the initial state
initialiseState = function () {
console.log("initialiseState");
// Are Notifications supported in the service worker?
if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
console.warn('Notifications aren\'t supported.');
return;
}
// Check the current Notification permission.
// If its denied, it's a permanent block until the
// user changes the permission
if (Notification.permission === 'denied') {
console.warn('The user has blocked notifications.');
return;
}
// Check if push messaging is supported
if (!('PushManager' in window)) {
console.warn('Push messaging isn\'t supported.');
return;
}
// We need the service worker registration to check for a subscription
navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
// Do we already have a push message subscription?
serviceWorkerRegistration.pushManager.getSubscription()
.then(function (subscription) {
if (!subscription) {
return;
}
// Keep your server in sync with the latest subscriptionId
sendSubscriptionToServer(subscription);
})
.catch(function (err) {
console.warn('Error during getSubscription()', err);
});
});
}
function subscribe() {
navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe()
.then(function (subscription) {
// The subscription was successful
// TODO: Send the subscription.endpoint to your server
// and save it to send a push message at a later date
return sendSubscriptionToServer(subscription);
})
.catch(function (e) {
if (Notification.permission === 'denied') {
// The user denied the notification permission which
// means we failed to subscribe and the user will need
// to manually change the notification permission to
// subscribe to push messages
console.warn('Permission for Notifications was denied');
} else {
// A problem occurred with the subscription; common reasons
// include network errors, and lacking gcm_sender_id and/or
// gcm_user_visible_only in the manifest.
console.error('Unable to subscribe to push.', e);
}
});
});
}
And the service worker looks like this:
self.addEventListener('push', showNotification)
self.addEventListener('notificationclick', closeNotificationAndOpenWindow)
function showNotification(event) {
console.log('Received a push message', event)
var title = 'Yay a message.'
var body = 'We have received a push message.'
var icon = '/images/icon-192x192.png'
var tag = 'simple-push-demo-notification-tag'
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
)
}
function closeNotificationAndOpenWindow(event) {
console.log('On notification click: ', event.notification.tag)
// Android doesn’t close the notification when you click on it
// See: http://crbug.com/463146
event.notification.close()
// This looks to see if the current is already open and
// focuses if it is
event.waitUntil(clients.matchAll({
type: "window"
}).then(function (clientList) {
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i]
if (client.url == '/' && 'focus' in client)
return client.focus()
}
if (clients.openWindow)
return clients.openWindow('/')
}))
}

Categories

Resources