Create notification by webworker - javascript

In article about notifications Mozzila says:
Note: This feature is available in Web Workers.
Worker can be created without any warnings
var worker = new SharedWorker('scripts/worker.js');
But when I try to do this inside shared worker:
var notification = new Notification("Hi there!");
It doesn't work. Webworker works fine, it does a XMLHttpRequest, it can read data from main thread and push messages to it but notification doesn't appear. I can't debug it because console is unavailable inside webworker. Permission was granted in main thread and the notifications are also available here.
If it is important I use Chrome 47.0.2526.111 m for developing and debugging. I noticed that Facebook invokes notifications even when FB tab is closed so I am trying to implement something similar.

You are doing something wrong. I had absolutely no problems running notifications in web workers.
This code works perfectly on jsfiddle:
Worker example
SharedWorker example
Please try following code:
main.js
var worker = new SharedWorker("worker.js");
worker.port.start();
Notification.requestPermission(function (permission) {
// If the user accepts, let's create a notification
if (permission === "granted") {
worker.port.postMessage({name:"notification"});
}
});
worker.js
function workerFN() {
function onmessage(e) {
switch(e.data.name) {
case "notification" :
console.log("Notification:");
var notification = new Notification("Hi there!");
break;
default:
console.error("Unknown message:", e.data.name);
}
}
self.onconnect = function(e) {
for(var i=0,l=e.ports.length; i<l; i++) {
e.ports[i].addEventListener('message', onmessage);
e.ports[i].start(); // Required when using addEventListener. Otherwise called implicitly by onmessage setter.
}
}
}
Also console works quite well for me in web workers.

Related

Why isn't a notification generated javascript?

This is my code
var notification = new Notification('notify');
Do I have to invoke the notification or should this be enough? I have also tried the code on the mdn website which is.
Notification.requestPermission();
// Let's check if the browser supports notifications
if (!("Notification" in window)) {
alert("This browser does not support desktop notification");
}
// Let's check whether notification permissions have already been granted
else if (Notification.permission === "granted") {
// If it's okay let's create a notification
console.log("granted")
var notification = new Notification("Hi there!");
}
// Otherwise, we need to ask the user for permission
else if (Notification.permission !== "denied") {
console.log("denied")
Notification.requestPermission().then(function (permission) {
// If the user accepts, let's create a notification
if (permission === "granted") {
var notification = new Notification("Hi there!");
}
});
}
// At last, if the user has denied notifications, and you
// want to be respectful there is no need to bother them any more.
}
The function is called and the word "granted" is logged so it seems like we permissions but for some reason I see no notification either on chrome or safari? I am using local host. Why am I not seeing a notification?
The code sample you provided works fine on my Chrome, you can test it in an online editor if you have any doubts.
Here you can try an example, i just scraped https://js.do/code/552731 with your sample.
Does it work here ?
I'm not sure the issue is related with the code sample you provided.
EDIT: After checking, it might be related to https/http issues, you might want to look into this thread

Chrome Extension with Service worker, update badge from a 'push' event

I have recently built a Chrome Extension that is coupled with a service worker, which recives push notifications via FCM, this is all working and my Service worker triggers correctly.
I want to be able to set the Chrome Extension Badge text from this function, as my server is updating the extension with the correct count.
Here is the function that I am currently using.
self.addEventListener('push', function(event) {
if (event.data) {
let data = event.data.json();
if (data.count){
// This is the only function that I can see when I debug the chrome obj
chrome.runtime.getBackgroundClient().then((bgClient) => {
console.log(bgClient)
})
}
}
});
I am aware of the
chrome.browserAction.setBadgeText({text: count});
function but this does not seem to be available from within the service worker, not can I see a way of accessing my background scripts.

service worker notificationclick event doesn't focus or open my website in tab

I use FCM push notification in my website and I want user can come into my website when He or She clicks on the push notification. Please notes that The user may be in other app or in other browser tab and I want when the user gets fcm notification the user will be able to come into my website by a click on the notification in the Firefox browser. For this reason, I used notificationclick event which Is available in the service worker. The code that I used is this:
self.addEventListener('notificationclick', event => {
console.log('On notification click: ', event.notification.tag);
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(clientList => {
for (let i = 0; i < clientList.length; i++) {
const client = clientList[i];
if (client.url === '/' && 'focus' in client) return client.focus();
}
if (clients.openWindow) return clients.openWindow('/');
})
);
});
It doesn't openwindow or focuses on my website tab. To debug the code I printed the clientList variable and It is an array with zero length.
The error that I get in the browser is this
On notification click:
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable firebase-messaging-sw.js:92
The above error refers to this line of code:
event.waitUntil(
OS: Mac
firefox:63.0.3
reactjs:16.2.0
Move your notificationclick handler BEFORE your line of code with messaging = firebase.messaging();. The FCM JS SDK installs its own global notificationclick handler and its e.waitUntil() call manages to (somehow) break the Firefox event object. If you install your global handler first, then it gets called first and so it will actually work. However, it will probably break the FCM handler in some obscure fashion.
This is, IMO, a bug in Firefox itself with regards to Service Workers rather than FCM, but FCM certainly contributes to the problem.
Relevant:
https://github.com/firebase/quickstart-js/issues/282 (same FCM bug)
https://bugzilla.mozilla.org/show_bug.cgi?id=1468935 (same FCM + Firefox bug, bad fix)
https://bugzilla.mozilla.org/show_bug.cgi?id=1313096 (the Firefox dev team doesn't have a way to test the callback in its Service Worker test suite, which makes this part of Firefox ripe for bugs)
https://bugzilla.mozilla.org/show_bug.cgi?id=1489800 (same browser bug, different product)
If the goal is to open a specific URL when the notification is clicked, there may be an easier way. You can sent a "click_action" field in the FCM notification payload.
Your payload would look something like this:
"notification" : {
"body" : "Sample body",
"title" : "Sample title",
"click_action": "http://google.com"
}
And when the notification is clicked, it will open google.com in this example.

HTML5 Web Notification Permission Issue

I'm trying to implement HTML5 Notification API in my chat application. When I'm working on my localhost, everything works fine (The browser prompts me whether i need to allow notification from this site or not).
But when i try to access my application running in my local machine from some other machine which all connected in the same network. The browser is not prompting anything.
To Sum up my problem:
http://localhost:3000/home - This works!
http://10.1.0.126:3000/home - This doesn't works this way. (Even if try my from my computer or from other computer)
This is the code I'm using for notification api implementation
function createNotification(response){
if(!('Notification' in window)){
console.log("This browser does not Notification")
}else{
if(Notification.permission === 'granted'){
createNotification(response) // function to createNotification from response
}else if(Notification.permission !== 'denied'){
Notification.requestPermission((permission) => {
if(permission === 'granted'){
createNotification(response)
}
})
}
function createNotification(response){
// Construct the Notification
let title = response.sender_name
let notificationOptions = {
body: response.message,
icon: default_profile_pic
}
// Close the Notification after 3 seconds
let notification = new Notification(title, notificationOptions)
setTimeout(notification.close.bind(notification),3000)
}
P.S: I'm using ReactJS, Redux for my front-end development.
In Chrome 62 and newer you cannot request notification api at all unless the site is https:// secured. (see issue 779612) If you do have https on the site you should be able to use notifications and background push notifications.
https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API/Using_the_Notifications_API

Inspecting WebSocket frames in an undetectable way

How I can read WebSocket frames of a web page in a Chrome extension or Firefox add-on, in a way that cannot be detected by the page?
Inspect WebSockets frames from a Chrome Dev Tools extension formulates a similar question, but developing a NPAPI plugin no longer makes sense because it will soon be removed.
Intercepting the WebSocket data is easy. Simply execute the following script before the page constructs the WebSocket. This snippet monkey-patches the WebSocket constructor: When a new WebSocket constructor is created, the snippet subscribes to the message event, from where you can do whatever you want with the data.
This snippet is designed to be indistinguishable from native code so the modification cannot easily be detected by the page (however, see the remarks at the end of this post).
(function() {
var OrigWebSocket = window.WebSocket;
var callWebSocket = OrigWebSocket.apply.bind(OrigWebSocket);
var wsAddListener = OrigWebSocket.prototype.addEventListener;
wsAddListener = wsAddListener.call.bind(wsAddListener);
window.WebSocket = function WebSocket(url, protocols) {
var ws;
if (!(this instanceof WebSocket)) {
// Called without 'new' (browsers will throw an error).
ws = callWebSocket(this, arguments);
} else if (arguments.length === 1) {
ws = new OrigWebSocket(url);
} else if (arguments.length >= 2) {
ws = new OrigWebSocket(url, protocols);
} else { // No arguments (browsers will throw an error)
ws = new OrigWebSocket();
}
wsAddListener(ws, 'message', function(event) {
// TODO: Do something with event.data (received data) if you wish.
});
return ws;
}.bind();
window.WebSocket.prototype = OrigWebSocket.prototype;
window.WebSocket.prototype.constructor = window.WebSocket;
var wsSend = OrigWebSocket.prototype.send;
wsSend = wsSend.apply.bind(wsSend);
OrigWebSocket.prototype.send = function(data) {
// TODO: Do something with the sent data if you wish.
return wsSend(this, arguments);
};
})();
In a Chrome extension, the snippet can be run via a content script with run_at:'document_start', see Insert code into the page context using a content script.
Firefox also supports content scripts, the same logic applies (with contentScriptWhen:'start').
Note: The previous snippet is designed to be indistinguishable from native code when executed before the rest of the page. The only (unusual and fragile) ways to detect these modifications are:
Pass invalid parameters to the WebSocket constructor, catch the error and inspecting the implementation-dependent (browser-specific) stack trace. If there is one more stack frame than usual, then the constructor might be tampered (seen from the page's perspective).
Serialize the constructor. Unmodified constructors become function WebSocket() { [native code] }, whereas a patched constructor looks like function () { [native code] } (this issue is only present in Chrome; in Firefox, the serialization is identical).
Serialize the WebSocket.prototype.send method. Since the function is not bound, serializing it (WebSocket.prototype.send.toString()) reveals the non-native implementation. This could be mitigated by overriding the .toString method of .send, which in turn can be detected by the page by a strict comparison with Function.prototype.toString. If you don't need the sent data, do not override OrigWebSocket.prototype.send.
There is an alternative to Rob W's method that completely masks any interaction with the page (for Chrome)
Namely, you can take out some heavy artillery and use chrome.debugger.
Note that using it will stop you from opening Dev Tools for the page in question (or, more precisely, opening the Dev Tools will make it stop working, since only one debugger client can connect). This has been improved since: multiple debuggers can be attached.
This is a pretty low-level API; you'll need to construct your queries using the debugger protocol yourself. Also, the corresponding events are not in the 1.1 documentation, you'll need to look at the development version.
You should be able to receive WebSocket events like those and examine their payloadData:
{"method":"Network.webSocketFrameSent","params":{"requestId":"3080.31","timestamp":18090.353684,"response":{"opcode":1,"mask":true,"payloadData":"Rock it with HTML5 WebSocket"}}}
{"method":"Network.webSocketFrameReceived","params":{"requestId":"3080.31","timestamp":18090.454617,"response":{"opcode":1,"mask":false,"payloadData":"Rock it with HTML5 WebSocket"}}}
This extension sample should provide a starting point.
In fact, here's a starting point, assuming tabId is the tab you're interested in:
chrome.debugger.attach({tabId:tab.id}, "1.1", function() {
chrome.debugger.sendCommand({tabId:tabId}, "Network.enable");
chrome.debugger.onEvent.addListener(onEvent);
});
function onEvent(debuggeeId, message, params) {
if (tabId != debuggeeId.tabId)
return;
if (message == "Network.webSocketFrameSent") {
// do something with params.response.payloadData,
// it contains the data SENT
} else if (message == "Network.webSocketFrameReceived") {
// do something with params.response.payloadData,
// it contains the data RECEIVED
}
}
I have tested this approach (with the linked sample modified as above) and it works.
Just to add an exception to #Xan answer (I don't have enough rep to post a comment on his answer so I add it here cause I believe it can save some time to someone else).
That example won't work if the WebSocket connection is established in a context that was loaded via about:, data: and blob: schemes.
See here for the related bugs: Attach debugger to worker from chrome devtools extension

Categories

Resources