chrome extensions message-passing - google-chrome

I'm trying to develop (for the moment!) a simple chrome extension using the message exchanging API.
My contentscript ask the background page for its url, and wait the background answer.
However, my contentscrpt never get the answer. Why? Thanks for your answer.
content_script.js
/**
* Retrieve the url or the page currently visited.
*/
chrome.extension.sendRequest({'action' : 'getUrl'}, function(response) {
alert(response.url);
});
background.html
...
function onRequest(request, sender, callback) {
sendResponse({'url' : sender.tab.url});
};
chrome.extension.onRequest.addListener(onRequest);

Your onRequest function has the final parameter named callback, but you call sendResponse in it. Assuming this is what your actual code looks like, you'll need to make the two names the same. If you inspect the background page in the developer tools, you should see a JavaScript exception about sendResponse being undefined.

Related

Is chrome.extension.onRequest deprecated?

I'm building a chrome extension and attempting to attach an event listener to this, but I'm not seeing anything in the console of the background page.
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
console.log('REFERRER', request.ref);
});
This code is in my main.js background page, all my other event listeners (chrome.tabs.onUpdated, chrome.extension.onMessage, etc) are all working fine though.
Yes, Request was deprecated in favor of 'Message'. So instead of onRequest you should use onMessage, and sendMessage as a replacement for sendRequest.

Message passing from extension to background page

I'm trying to create a page action extension in chrome. I have an html page corresponding to the popup that gets displayed on clicking the page action. I have included a script file popup.js in this html page. From this page I'm trying to send a message to a background js file background.js. The problem is that I'm calling sendRequest only once from popup.js but I'm receiving it in the background page multiple times. I'm doing a file action there which results in script errors because of concurrent access. I'm pasting the code related to message passing here
extension file - popup.js
chrome.extension.sendRequest({"intent" : "read"}, function (message) {
console.log(message);
});
background page - background.js
(function(){
var fileName = "credentials.txt";
var fileSystem;
function checkUrl(tabId, changeInfo, tab) {
if(/https?:\/\/.*?\/olc/.test(tab.url)) {
chrome.pageAction.show(tabId);
chrome.extension.onRequest.addListener(function (request, sender, callback) {
callback("printed");
});
}
}
chrome.tabs.onUpdated.addListener(checkUrl);
})();
The listener is called 4 times in this case. The callback will be called the first time. The next 3 times it gives an error saying Could not send response: Cannot send a response more than once per chrome.extension.onRequest listener per document (message was sent by extension kaejjpmlibijbgbgcfodphlkcjjkmjlk). Can anyone help me with this?
They're supposed to work only once.
You can either use the long-lived messaging system or reattach the same handler over and over again upon receiving the message from the content script.
Use chrome.extension.getBackgroundPage(). You will have access to background page from yor popup.
Or write to localStorage and use listener.
window.addEventListener('storage', function (e) {}, false);
You will have problems with memory leak if you will use chrome.extension.sendRequest for comunication between popup and background.html.

Modify url location in chrome extensions & stop the initial request

I've made an extension who's purpose is to redirect urls.
I.e: www.google.com becomes: www.mysite.com/?url=www.google.com
I came across this post:
How to modify current url location in chrome via extensions
The problem I'm having is that the url's are both processed. The tab initially loads up google.com and only after it's finished my request is shown ( www.mysite.com/?url=www.google.com).
Is there any way to stop the initial request from being processed?
Something like:
chrome.tabs.onUpdated.addListener(function(tabId,obj,tab){
update.stop() // ??????????? Here I'm missing...
chrome.tabs.update(tabId,{url:....}, function callback); // My update stuff..
});
Thoughts?
thank you all.
You're looking for the webNavigation API.
You can register listeners to handle user navigation by modifying or blocking the request on the fly.
In the example below, when a user navigate to www.google.com, before the page even start loading onBeforeNavigate is fired and you can redirect the user to the CSS validation page for that URL:
chrome.webNavigation.onBeforeNavigate.addListener((details) => {
if(details.url.indexOf("www.google.com") !== -1)) {
chrome.tabs.update(details.tabId, {
url: "https://jigsaw.w3.org/css-validator/validator?uri=" + details.url
});
}
});
Remember to add the "webNavigation" permission to your extension manifest to get this functionality enabled.
chrome.tabs.onUpdated is fired two times per tab load - once a tab starts loading, and another time when it finishes loading. If you attach your update to the tab start loading event then it should work relatively quickly. You will still see original url being loaded for a brief moment, but it won't wait until it finishes, as you are describing.
chrome.tabs.onUpdated.addListener(function(tabId,obj,tab){
if(obj.status == "loading") {
chrome.tabs.update(tabId,{url:....}, function callback);
}
});
I don't think there is a more efficient solution at the moment.

Can chrome extension background pages have multiple listeners?

I'm building a chrome extension and trying to get data from twitter and then pass that to my contentscript. I'm having a lot of problems with this. I'm able to get the data from the remote site but can't seem to pass it to my content script. I have a listener for when i click the icon using chrome.extension.onclick.addlistener(functionname);. This gets the data. The Problem is once i get the data, i need to send a response to the request from my content script. So i'm also calling chrome.extension.Onrequest.addlistener(functioname);. Before i go on trying to figure out what's wrong with the code, is it allowed to have 2 listeners for 2 separate events in the same page as i've done or can you only have one listener?
I know this is a crazy old question, but I came across this while experiencing a related issue and wanted to share in case it was useful for anyone else.
Make sure you're only calling the sendResponse method at most once if you do have multiple listeners. From the docs:
sendResponse: Function to call (at most once) when you have a response.
The argument should be any JSON-ifiable object. If you have more than
one onMessage listener in the same document, then only one may send a
response. This function becomes invalid when the event listener
returns, unless you return true from the event listener to indicate
you wish to send a response asynchronously (this will keep the message
channel open to the other end until sendResponse is called).
If you do a quick search on Stackoverflow, you will see many examples with code on how to send messages from background page to content script:
https://stackoverflow.com/search?tab=relevance&q=content%20script%20background%20page
For more information how to do this, you can follow the docs themselves, they have great examples:
http://code.google.com/chrome/extensions/messaging.html
From the documentation (copy paste):
content_script.cs
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
else
sendResponse({}); // snub them.
});
background.html
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
The fact that you have created a listener for the onClick event and a listener for the onRequest event is not a problem. You can tell by typing out chrome.onClick and chrome.OnRequest at the console for the background page; you'll see they are each instances of type 'chrome.Event'.
If you think about it, if you were only able to create one listener it would greatly reduce your ability to write something useful since you could only respond to one of { onrequest, onclick, ontabchange, onconnect, ondisconnect, etc. }

How do I access the popup page DOM from bg page in Chrome extension?

In Google Chrome's extension developer section, it says
The HTML pages inside an extension
have complete access to each other's
DOMs, and they can invoke functions on
each other. ... The popup's contents
are a web page defined by an HTML file
(popup.html). The popup doesn't need
to duplicate code that's in the
background page (background.html)
because the popup can invoke functions
on the background page
I've loaded and tested jQuery, and can access DOM elements in background.html with jQuery, but I cannot figure out how to get access to DOM elements in popup.html from background.html.
can you discuss why you would want to do that? A background page is a page that lives forever for the life time of your extension. While the popup page only lives when you click on the popup.
In my opinion, it should be refactored the other way around, your popup should request something from the background page. You just do this in the popup to access the background page:
chrome.extension.getBackgroundPage()
But if you insist, you can use simple communication with extension pages with sendRequest() and onRequest. Perhaps you can use chrome.extension.getViews
I understand why you want to do this as I have run into the problem myself.
The easiest thing I could think of was using Google's method of a callback - the sendRequest and onRequest methods work as well, but I find them to be clunky and less straightforward.
Popup.js
chrome.extension.getBackgroundPage().doMethod(function(params)
{
// Work with modified params
// Use local variables
});
Background.html
function doMethod(callback)
{
if(callback)
{
// Create/modify params if needed
var params;
// Invoke the callback
callback(params);
}
}
As other answers mention, you can call background.js functions from popup.js like so:
var _background = chrome.extension.getBackgroundPage();
_background.backgroundJsFunction();
But to access popup.js or popup.html from background.js, you're supposed to use the messages architecture like so:
// in background.js
chrome.runtime.sendMessage( { property: value } );
// in popup.js
chrome.runtime.onMessage.addListener(handleBackgroundMessages);
function handleBackgroundMessages(message)
{
if (message.property === value)
// do stuff
}
However, it seems that you can synchronously access popup.js from background.js, just like you can synchronously access the other way around. chrome.extension.getViews can get you the popup window object, and you can use that to call functions, access variables, and access the DOM.
var _popup = chrome.extension.getViews( { type: 'popup' } )[0];
_popup.popupJsFunction();
_popup.document.getElementById('element');
_popup.document.title = 'poop'
Note that getViews() will return [] if the popup is not open, so you have to handle that.
I'm not sure why no one else mentioned this. Perhaps there's some pitfalls or bad practices to this that I've overlooked? But in my limited testing in my own extension, it seems to work.