How to properly use sendResponse() in MV3 Chrome extension [duplicate] - google-chrome-extension

This question already has answers here:
chrome extension - sendResponse not waiting for async function [duplicate]
(1 answer)
chrome extension - how i can await for chrome.runtime function?
(1 answer)
Closed 12 months ago.
I'm playing around with Promises available in Chrome extensions Manifest V3, but I'm not getting the expected results. What I'm trying to achieve: store some data from a browser action popup, then get a response back after the data is saved. Here's what I have so far:
background.js (service worker)
async function handleMessage(message, sender, sendResponse) {
switch (message.request) {
case 'setTimestamp':
await chrome.storage.local.set(message.data);
sendResponse({
status: chrome.runtime.lastError ? 'error' : 'ok'
});
break;
default:
sendResponse(null);
}
}
chrome.runtime.onMessage.addListener(handleMessage);
popup.js
// Event handler for button in popup.html
async function setTimestamp() {
const response = await chrome.runtime.sendMessage({
request: 'setTimestamp',
data: {
timestamp: performance.now()
}
});
console.log('setTimestamp response', response);
}
The timestamp is being saved successfully, but the response in popup.html is undefined instead of {status: 'ok'} that I was expecting. Can someone please point out what I'm doing wrong?
(Note: I'm aware you can use storage.local.set() directly from the popup and validate that the data was saved successfully by detecting chrome.runtime.lastError in the callback, but I wanted to use the new aync/await pattern above.)

Related

sendMessage from backgrond page to another backgrond page chrome extension mv3

Migrating extension mv2 to mv3 version. There was a problem with sending messages from one background page to another.
There are two utils (background pages), in order to use the methods of the first in the second and the second in the first, do I need to send messages between these two background pages? or through the main service worker?
I send messages without a service-worker, directly from one utility to another.
chrome.runtime.sendMessage({ type: 'typeMessage' }, (res) => {
return res;
});
But in another utility the listener does not receive this message
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
const { type, payload } = message;
switch (type) {
case 'typeMessage':
// any code
return;
default:
return Promise.resolve(`Message received: ${type}`);
}
});
Please tell me what am I doing wrong?
Sending messages from jsx (foreground) to js (service-worker) works. But from js (background) to another js (background) no.

chrome.devtools.network.onRequestFinished - console.log not executed

I have this code to create a devtools panel in a chrome extension. For learning proupose I want to inspect network requests of a certain website and get the body of them.
chrome.devtools.panels.create('Spotify test', '', '/index.html');
chrome.devtools.network.onRequestFinished.addListener( (request) => {
//console.log(request);
if(request.method === 'GET' && request.response.status === '206' ){
console.log(request);
request.getContent( (content, encoding) => {
console.log(content, encoding);
});
}
});
The problem is that the if(request.method === 'GET' && request.response.status === '206' ) will not be executed, I'm able to log the request object of the callback only if I put it outside the statement. I want to log only requests that are using the GET method and that have the 206 status code. As I read in the documentation, on the request object I can use the getContent() method to get the body of the response, is this right? Is there any error in the code that will prevent to the console.log() to be fired?
NB: I'm using the devtools console that is opened by clicking the inspect menu voice inside the panel I've added.
request.request.method instead of request.method

Chrome extension - result is always null

I've just started playing with Chrome extensions.
In my content.js I have following
chrome.runtime.sendMessage("", function(response){
//some logic
});
And in background.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
sendResponse(someFunction);
return true;
});
function someFunction(para) {
//logic
}
The issue is, the response in content.js is always undefined... The similar posts on this site is usually due to asynchronous calls such as ajax, but I'm not doing anything asynchronously and I'm returning true which according to the docs returns the method... I can only assume my logic is some how backwards?
What have I done wrong?
you cant send a function ("someFunction") as a response. the response object must be serializable.

chrome extension messaging from background to content script gives :Port error: Could not establish connection. Receiving end does not exist [duplicate]

For my Chrome extension, I am attempting to post selected text to a PHP webpage. A solved question on this website (Chrome Extension: how to capture selected text and send to a web service) has helped me a lot in achieving this, but I want a different way of posting the text.
Instead of XMLHttpRequest as mentioned there, I want to send a hidden JS form from the content script. This method allows me to view or change the text before importing it to the database.
The problem is to get the trigger from the background to the content script. I already have a message the other way, so using the function(response) is desired. However, outside the “sendMessage”, I can’t listen for the response.cmd. And inside the “sendMessage”, I can’t get the response.cmd to trigger a function. Is there a solution for this, other than sending an all new message from the background script?
The code I am referring to:
Background.js
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
if(request.cmd == "createSelectionMenu") {
sendResponse({cmd: "saveText"}); //Do things
}
});
Content_script.js
chrome.extension.sendMessage({ cmd: "createSelectionMenu", data: selectedText },
function(response) {
if(response.cmd == "saveText") {
createForm();
}
}
});
What I do is following:
I keep track of my opened tabs
content script:
// connect to the background script
var port = chrome.extension.connect();
background script
// a tab requests connection to the background script
chrome.extension.onConnect.addListener(function(port) {
var tabId = port.sender.tab.id;
console.log('Received request from content script', port);
// add tab when opened
if (channelTabs.indexOf(tabId) == -1) {
channelTabs.push(tabId);
}
// remove when closed/directed to another url
port.onDisconnect.addListener(function() {
channelTabs.splice(channelTabs.indexOf(tabId), 1);
});
});
Now I can notify all my registered tabs (i.e. content scripts) from my background script when a certain action happened:
var notification = { foo: 'bar' };
for(var i = 0, len = channelTabs.length; i < len; i++) {
chrome.tabs.sendMessage(channelTabs[i], notification, function(responseMessage) {
// message coming back from content script
console.log(responseMessage);
});
}
And again, on the other side in the content script, you can add a listener on these messages:
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
if (request.foo == 'bar') {
executeStuff();
// if a callback is given:
sendResponse && sendResponse('success');
}
});
It's a bit of a brainf*ck, because it's redundant at some places. But I like it best that way, because you can wrap it and make it a bit easier.
If you want to see how I am using this, see my repository on GitHub: chrome-extension-communicator.

Message isn't passed between background.html and popup.html

I'm trying to pass data that is saved in sessionStorage from background.html to popup.html
background.html:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
data = sessionStorage.getItem(request.tabId);
alert(data);
sendResponse({ data: data });
});
and in popup.html:
chrome.tabs.getSelected(null, function(tab) {
chrome.extension.sendRequest({ tabId: tab.id }, function(response) {
alert(response.data);
});
});
The popup is opened by a pageAction button, when I click the button I get an alert box with "null" on the popup and then an alert box with the data that I stored in sessionStorage on the background!
Any ideas how to fix this?
You don't need to use message/request APIs. I think this response may help you.
You also don't need sessionStorage, just store your data in a global variable of the background page. It will persist until the browser is closed or until the extension is restarted.
So, here is how I would rewrite your code:
background.html:
var data = {}; // Object storing data indexed by tab id
and in popup.html:
chrome.tabs.getSelected(null, function(tab) {
alert(chrome.extension.getBackgroundPage().data[tab.id]);
});
Note that chrome.tabs.getSelected is deprecated since Chrome 16, so popup code should be:
chrome.windows.getCurrent(function(win) {
chrome.tabs.query({'windowId': win.id, 'active': true}, function(tabArray) {
alert(chrome.extension.getBackgroundPage().data[tabArray[0].id]);
});
});
Well, I've done something dumb.
I inspected the background page by opening chrome-extension://[extension-id]/background.html in a tab instead of clicking on "inspect active views: background.html" in the extensions management page. This caused the tab to catch the request and call sendResponse, but the popup expected the REAL background page to call sendResponse (and if I understand Google's documentation regarding message passing, the fact that sendResponse was called twice is root of the problem, because the first call clears the request object)

Resources