I can't store data from setBackgroundMessageHandler - javascript

I'm using firebase for pushing notification. When I get the notification in the background, I get data. I want to save this data in the local storage, but I get this error
TypeError: Cannot read property 'setItem' of undefined
importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-messaging.js');
firebase.initializeApp({
messagingSenderId: '628214501041'
});
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function (payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
var notificationTitle = 'Background Message Title';
var notificationOptions = {
body: 'Background Message body.',
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
self.addEventListener('push', function (event) {
var pushData = event.data.json();
try {
if(self.window.localStorage){
self.localStorage.setItem('notificationData' , JSON.stringify(pushData) ) ;
// }
}
catch (err) {
console.log('Push error happened:', err);
}
});

The self variable you're using in your code is not something that is defined by default.
But from your code, you're probably looking for:
if(self.window.localStorage) {
self.window.localStorage.setItem('notificationData' , JSON.stringify(pushData) ) ;
}
So the change there is using self.window.localStorage, instead of self.localStorage in the second line.

Well, you can't access the local storage or the session storage from your service worker because it have no access to the DOM.
You should use CacheAPI
Or for persisting data and access it from your service worker and window instance use:
IndexedDB
This is in the lifecyle of your service worker and can also be accessed by the window object.

Related

Background notifications not showing

I am new to firebase cloud messaging and I am trying to setup a notification system on nodeJS. I followed the docs on the service-worker and everything, however there is a problem that notifications are not being shown by the browser even though they reach the client.
service worker code :
importScripts("https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js");
// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
messagingSenderId: "901639143723"
});
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log(
"[firebase-messaging-sw.js NOIS] Received background message ",
payload
);
var notificationTitle = "Background Message Title";
var notificationOptions = {
body: "HI"
icon: "/firebase-logo.png"
};
console.log(
self.registration.showNotification(notificationTitle, notificationOptions)
);
return self.registration.showNotification(
notificationTitle,
notificationOptions
);
});
[![enter image description here][1]][1]
// Customize notification here

Uncaught (in promise) ReferenceError: modifyVideoDoneWindow is not defined - ServiceWorker

I am trying to implement Google Push Notifications, but I am having a problem with with service-worker. Everything works fine, but suddenly I started receiving this error message in the console.
When I call the function modifyVideoDoneWindow(payload) from my onMessage function( When the user in the page), there is no problem.
I think the problem is about scope..
Error: "Uncaught (in promise) ReferenceError: modifyVideoDoneWindow is not defined"
// Initialize the Firebase app in the service worker by passing the config.
firebase.initializeApp(config);
self.addEventListener('notificationclick', (event) => {
event.waitUntil(self.clients.openWindow('http://localhost:8080/#videodone'));
event.notification.close();
});
// Retrieve an instance of Firebase Messaging so that it can handle background messages.
const messaging = firebase.messaging();
// Handle Messages, when the page is closed.
messaging.setBackgroundMessageHandler( (payload) => {
console.log('Received background message in the service worker PAYLOAD', payload);
console.log("Notification status: ", payload.data.status);
// Customize notification here
var notificationTitle = 'Video Making Tool';
var notificationOptions = {
body: 'Your video is ready.',
icon: '/logo......'
};
modifyVideoDoneWindow(payload);
return self.registration.showNotification(notificationTitle, notificationOptions);
});

FCM default onMessage override?

I have a small web app which receives FCM messages, have a service worker, handles background messages and all are well. The Service Worker will receive the messages and will post them back to the main page so they can be displayed on page. That is for the background messages.
My problem is with the foreground messages being handled by some default onMessage() which passes them as well to the main page as messages encapsulated in a big message. So, lets say, if I have defined my own onMessage() function in a .js or in the main page itself, this message will be called and then the default one as well, which causes the message to be handled twice.
Below is the message I am receiving:
The code in the service worker is:
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js');
var config = {
apiKey: "AIzaSyBoi6gB1BHKxFBt58JJ4phWiZr9BKJaphI",
authDomain: "webmessaging-7bef1.firebaseapp.com",
databaseURL: "https://webmessaging-7bef1.firebaseio.com",
projectId: "webmessaging-7bef1",
storageBucket: "webmessaging-7bef1.appspot.com",
messagingSenderId: "649072625962"
};
// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
'messagingSenderId': '649072625962'
});
const messaging = firebase.messaging();
self.addEventListener('notificationclick', function (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({
includeUncontrolled: true,
type: "all"
})
.then(function (clientList) {
console.log('Clients Count: ', clientList.length);
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i];
var clientUrl = client.url;
console.log('Client URL:', client.url);
if ((clientUrl.indexOf("localhost") != -1) && 'focus' in client)
return client.focus();
}
if (clients.openWindow) {
return clients.openWindow('https://deanhume.github.io/typography');
}
})
);
});
messaging.setBackgroundMessageHandler(function (payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = payload.data.title;
const notificationOptions = {
body: payload.data.body,
icon: '/fcm-logo.png'
};
clients.matchAll({
includeUncontrolled: true,
type: "all"
})
.then(function (clientList) {
console.log('Clients Count: ', clientList.length);
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i];
var clientUrl = client.url;
console.log('Client URL:', client.url);
if ((clientUrl.indexOf("localhost") != -1) && 'focus' in client) {
// client.postMessage(payload.data);
}
}
})
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
If I remove my onMessage() handler, I will still get the message posted by the default onMessage() handler.
Please, advise.
Thanks...
[UPDATE]
After some thorough checkups, I have come to some conclusion that the issue appears to be in the fact that I have the following two functions which appear to be doing exactly the same thing by receiving messages sent to the page.
This one is is supposed to receive the messages when the page is in the foreground and having focus.
messaging.onMessage(function (payload) {
console.log('Message received: ', payload);
alert(payload.data.title);
// Get the data passed by the message and display on the page...
document.getElementById('Select1').innerHTML += "<option>" + payload.data.title + "</option>";
});
And this one is mean to be receiving the data passed by the service worker when the message is received while the page is at the background and not having focus.
// Listen to messages from service workers.
navigator.serviceWorker.addEventListener('message', function (event) {
console.log("Got reply from service worker: ", event);
// Get the data passed by the message and display on the page...
document.getElementById('Select1').innerHTML += "<option>" + event.data.title + "</option>";
});
So, basically, I am listening to the messages via two handlers at the same place and at the same time which results in the messages being handled twice at the same time...
Any advise how I can properly organize this code?
A couple of notes:
1- You should not include config details in the service worker (as it resides on the client's end) and restrict it to the required:
firebase.initializeApp({
'messagingSenderId': '649072625962'
});
2- messaging.setBackgroundMessageHandler is only triggered in the case of the background.
3- messaging.onMessage() you don't define in the service worker but rather in a .js as you mentioned to handle the cases of the foreground scenarios and will be triggered only in that case (there is no default definition of it until you define it)

Firebase messaging returns success, but webapp not receiving message

I'm using the Firebase cloud messaging API and sending a message to a webapp. Everything seems to work fine, and sending the message returns success, but onMessage() which is supposed to receive the message, is never called.
GCM Connection inside chrome in chrome://gcm-internals is connected.
I also tried Firefox, same thing.
The response from firebase looks good:
{'multicast_ids': [5162553035531497690], 'success': 1, 'failure': 0, 'canonical_ids': 0, 'results': [{'message_id': 'https://updates.push.services.mozilla.com/m/...'}], 'topic_message_id': None}
However, onMessage in the webapp is never called, and I don't know why because I'm getting no errors and everything seems fine.
Here's my JS code:
<link rel="manifest" href="/cryptoalert/manifest.json">
<script src="https://www.gstatic.com/firebasejs/4.6.2/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "...",
projectId: "...",
messagingSenderId: "..."
};
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.requestPermission()
.then(function() {
console.log('Notification permission granted.');
// TODO(developer): Retrieve an Instance ID token for use with FCM.
// ...
})
.catch(function(err) {
console.log('Unable to get permission to notify.', err);
});
// Get Instance ID token. Initially this makes a network call, once retrieved
// subsequent calls to getToken will return from cache.
messaging.getToken()
.then(function(currentToken) {
if (currentToken) {
console.log(currentToken);
//sendTokenToServer(currentToken);
//updateUIForPushEnabled(currentToken);
} else {
// Show permission request.
console.log('No Instance ID token available. Request permission to generate one.');
// Show permission UI.
updateUIForPushPermissionRequired();
setTokenSentToServer(false);
}
})
.catch(function(err) {
console.log('An error occurred while retrieving token. ', err);
showToken('Error retrieving Instance ID token. ', err);
setTokenSentToServer(false);
});
messaging.onMessage(function(payload) {
console.log("Message received. ", payload);
// ...
});
</script>
And here's the server code:
from pyfcm import FCMNotification
push_service = FCMNotification(api_key="...")
# Send to multiple devices by passing a list of ids.
#Get registration ID from
registration_ids = ['from console.log(currentToken)']
message_title = "Uber update"
message_body = "Hope you're having fun this weekend, don't forget to check today's news"
result = push_service.notify_multiple_devices(registration_ids=registration_ids, message_title=message_title, message_body=message_body)
print(result)
I faced the same problem. It was resolved after i published from local host with self-issued SSL to real site with trusted SSL. Check the following steps:
firebase-messaging-sw.js, manifest.json are in root and available
There is a real SSL (not self-trusted)
Code of firebase-messaging-sw.js like:
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js');
firebase.initializeApp({
messagingSenderId: "830*********"
});
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function (payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
var notificationTitle = 'Background Message Title';
var notificationOptions = {
body: 'Background Message body.',
icon: '/firebase-logo.png'
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});

Get app initialized firebase instance in front GUI in javascript

I'm new to service workers and firebase web with javascript. I want to retrieve payloads from firebase to show it via a notification to the user. Now I'm struggling with the following problem.
What works
When I using the following script to register a service worker, I will get a succeeded response.
index.html
<p id="status"></p>
<script src="https://www.gstatic.com/firebasejs/4.3.1/firebase.js"></script>
<script>
if ('serviceWorker' in navigator) {
// Override the default scope of '/' with './', so that the registration applies
// to the current directory and everything underneath it.
navigator.serviceWorker.register('sw.js', {scope: './'}).then(function (registration) {
// At this point, registration has taken place.
// The service worker will not handle requests until this page and any
// other instances of this page (in other tabs, etc.) have been
// closed/reloaded.
document.querySelector('#status').textContent = 'succeeded';
}).catch(function (error) {
// Something went wrong during registration. The service-worker.js file
// might be unavailable or contain a syntax error.
document.querySelector('#status').textContent = error;
});
} else {
// The current browser doesn't support service workers.
var aElement = document.createElement('a');
aElement.href = 'http://www.chromium.org/blink/serviceworker/service-worker-faq';
aElement.textContent = 'unavailable';
document.querySelector('#status').appendChild(aElement);
}
</script>
sw.js
importScripts('https://www.gstatic.com/firebasejs/4.3.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.3.0/firebase-messaging.js');
var config = {
apiKey: "MY_API_KEY",
authDomain: "project-xxxxx.firebaseapp.com",
databaseURL: "https://project-xxxxx.firebaseio.com",
projectId: "project-xxxxx",
storageBucket: "project-xxxxx.appspot.com",
messagingSenderId: "xxxxx"
};
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function (payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = 'Background Message Title';
const notificationOptions = {
body: 'Background Message body.',
icon: '/firebase-logo.png'
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
What's the problem
Now my problem is, that I want to handle with the messaging constant from the service worker on the index.html because the console tells me that the following script only works in the window context:
Uncaught FirebaseError: Messaging: This method is available in a
Window context. (messaging/only-available-in-window).
messaging.requestPermission()
.then(function () {
console.log('Notification permission granted.' + messaging.getToken());
messaging.getToken()
.then(function (currentToken) {
if (currentToken) {
console.log(currentToken);
} else {
// Show permission request.
console.log('No Instance ID token available. Request permission to generate one.');
// Show permission UI.
}
})
.catch(function (err) {
console.log('An error occurred while retrieving token. ', err);
});
})
.catch(function (err) {
console.log('Unable to get permission to notify.', err);
});
Now how can I get the firebase instance from the registration or is that a wrong theory?
The window context is not available to the Service Worker. It's also not possible to share anything from the window to the SW and vice versa (so you cannot declare a variable and access it from both). From the error message, it seems that the Firebase libraries depend upon the window context so you cannot use them inside ths SW script.
I'm not sure how to handle what you're trying to do.

Resources