I am trying to use chrome.windows.onCreated but I got Uncaught TypeError: Cannot read property 'onCreated' of undefined. I noticed in the samples, all calls to chrome.* API's seem to originate from background scripts? Can I not use them in content scripts?
I want to trigger clicks in my browser. Then get some information (scrape) in popup window. For that I think I will need to know when a window is opened. So I need windows.onCreated? Can I use that in content scripts? Or how will I combine background and content scripts?
From the documentation for Content scripts:
However, content scripts have some limitations. They cannot:
Use chrome.* APIs (except for parts of chrome.extension)
Use variables or functions defined by their extension's pages
Use variables or functions defined by web pages or by other content scripts
These limitations can indirectly be avoided, mainly by sending messages within the extension. The documentation offers several examples which involves message passing. Prior Chrome 20, the message API methods was called onRequest and sendRequest. Since version 20, they're called onMessage and sendMessage.
Here's an answer which mentions the steps how to pass a message from a content script to a popup:
https://stackoverflow.com/a/11617742
Related
I have a very simple background page for a Chrome extension:
chrome.runtime.onInstalled.addListener((reason) => {
console.log(reason);
});
The background page runs when my extension is loaded:
The extension also has a popup that runs getBackgroundPage(), using:
const serviceWorkerWindow = await chrome.runtime.getBackgroundPage();
This fails with:
Uncaught (in promise) Error: You do not have a background page.
How do I make getBackgroundPage() work?
The getBackgroundPage() method doesn't retrieve the background script, it retrieves the window object associated with the background script. As you know, Manifest V3 doesn't use background scripts, it uses a service worker. Service workers by definition do not have access to window objects.
What is your use case? Maybe I could suggest an alternative approach.
Answering my own question based on #wOxxOm's comment. If wOxxOm writes their own answer I'll mark that as correct.
My expectation based on Google's documentation was that getBackgroundPage():
retrieves the JavaScript 'window' object for the background page running inside the current extension/app.
In modern JS terms, this would be the globalThis for the service worker (the service workers is still referred to as background in manifest v3.
As wOxxOm said.
This API won't work. The documentation is simply outdated because the ManifestV3 team consists of just a few devs who don't have time to do everything.
Essentially the Chrome Extension documentation is not adequately maintained. There is an outstanding W3C issue on the topic of whether getBackgroundPage should work with service workers - thanks #erosman. The best way to communicate between a popup and a background service worker is via extension messaging. Ie:
chrome.runtime.sendMessage()
And:
chrome.runtime.onMessage.addListener()
I'm working on a Chrome extension that among other things supports a page with multiple dynamically created iframes in it, pointing to multiple different domains. I need to load a content script into each of those iframes, ideally without loading it into every page.
There's a separate content script that's running on all those iframe pages, which can detect that it's in an applicable iframe, and I'd like it to load this other content script. After some wrangling, it can get the frameId of that iframe, but chrome.tabs.executeScript() takes only tabId, not frameId, so the script loads in the top-level page, not the desired iframe.
Note that the script I want to inject needs to run as a content script, with access to the available Chrome APIs.
Is it possible to do this? How?
Update: Ach, you're of course right wOxxOm, that "frameId can be specified inside executeScript's second parameter". Thank you again, make that an answer and I'll accept it. I need to read more carefully, apparently. I'm a long-time programmer, but new to Chrome extensions, there's a lot to absorb.
Secondary question: It appears that I need to add <all_urls> or http://*/* and https://*/*, permission to the manifest for this to be allowed. The main content_script that's doing this has similar match patterns, and I could add this secondary script there too, but it's actually only needed for pages shown in these iframes, so this seems better to me. Are there other downsides to doing it this way, or is there some better approach, other than xhr/eval?
I am working on a Chrome extension that needs to call a native application.
As per Google documentation, we are using the chrome.runtime.connectNative method.
However in our extension, it seems that the chrome.runtime object has no method 'connectNative'. When we display the list of methods of the chrome.runtime object, we get the following list (printed by console.log("" + Object.getOwnPropertyNames(chrome.runtime));
getManifest,getURL,reload,requestUpdateCheck,connect,sendMessage,onConnect,onMessage,id
We are using Chrome 31.0.1650.63 on MacOS X 10.8.5 . We have also tried with Chrome Canary (version 34.0.1767.0 canary), we have the same error, with a slightly different list of methods for chrome.runtime:
getManifest,getURL,setUninstallUrl,reload,requestUpdateCheck,connect,sendMessage,onConnect,onMessage,id
So, in both cases (regular Chrome and Chrome Canary), we don't have the 'connectNative' method.
This does not seem to be a permissions problem, our extension manifest does have "nativeMessaging" in the permissions attribute. When we click on the permissions link in the Chrome extension settings, we can see that the extension can "communicate with cooperating native applications".
(sorry I couldn't post screenshots or the full manifest, StackOverflow won't let me paste things that even remotely look like I'm posting an image since I don't have enough reputation....)
Are we missing something ?
The list of properties of chrome.runtime you are getting indicates that your code is running as a content script. Most chrome.* APIs are not available to content scripts. They can only be used from background or event pages, popups, or other extension views you define. So you can use regular extension messaging from your content script to a background or event page, which in its turn can call your native app.
I have an extension which provides a number of services to any web app that requires them. I had been assuming that a web app could use chrome.runtime.sendMessage(ext-id,message), but when I try, there is no sendMessage function on chrome.runtime.
Have I misunderstood where sendMessage can be used, and is there another technique that I can use to communicate from an arbitrary web app to my extension?
There are a few options.
First, http://developer.chrome.com/extensions/manifest/externally_connectable.html is the closest to how you're thinking about it right now. You're expecting to be able to add proprietary, Chrome-specific functionality to arbitrary web pages. externally_connectable will give you a limited version of (see http://developer.chrome.com/extensions/messaging.html#external-webpage for an example), but only for specific web pages (e.g., *.yourdomain.com but not *.com).
Second, you can postMessage from your web page to a content script (see http://developer.chrome.com/extensions/content_scripts.html#host-page-communication), which can do anything a content script can. If you need chrome.* APIs at that point, you can message from the content script to your extension's page, which has access to any chrome.* APIs that it's asked for.
Finally, depending on what your "number of services" actually is, you can always executeScript another script directly into a target webpage, which is similar to forcing the webpage to include it as if it were another <script> tag. (Only similar to, not identical to, because the injection typically happens after the page has loaded.)
I come from Chrome extensions, so I'm used to defining when a file should be injected by setting run_at, e.g., to document_start for injection before DOM construction. Is there an equivalent for Firefox addons?
Yes, the equivalent would be the content-document-global-created notification. An extension can add an observer for that notification and then do something with the window - like injecting a content script. See How to override JS function from a firefox extension? for one example of using this notification.
If you use the Add-on SDK it will do this job for you. The page-mod package supports a contentScriptWhen parameter - you can use "start" as its value and the content script will be injected before any page scripts get a chance to run.