Google chrome extension error - google-chrome

chrome-extension, stucked with the error
Uncaught TypeError: Cannot read property 'sendRequest' of undefined
here is my code
manifest.json
{
"manifest_version": 2,
"name": "blah",
"version": "1.0",
"description": "blah",
"browser_action": {
"default_icon": "icon.png"
},
"background": "bg.html", // change to your background page
"permissions": ["http://*/*", "tabs"], //need permission to access all pages & tabs
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"], // run for http & https pages
"js": ["key_event.js"], // key_event.js is injected to the page, this handles key press
"run_at": "document_start" // run before everything else, else there will be conflicts at pages which accept keyboard inputs ( eg:google search)
}
]
}
key_event.js
if (window == top) {
window.addEventListener('keyup', doKeyPress, false); //add the keyboard handler
}
function doKeyPress(e){
if (e.keyCode == 17){ // if e.shiftKey is not provided then script will run at all instances of typing "G"
alert("pressed");
chrome.extension.sendRequest({redirect: "https://www.google.co.in"});//build newurl as per viewtext URL generated earlier.
}
}
bg.html
chrome.extension.onRequest.addListener(function(request, sender) {
chrome.tabs.update(sender.tab.id, {url: request.redirect});
});
plz help me

As already mentioned in comments
The background section of manifest version 2 has to be like
"background": {"scripts": ["bg.js"]}
There is no background page, only background scripts. So you'll have to move your code from bg.html to bg.js and remove all the extra HTML from it.
chrome.extension.sendRequest and chrome.extension.onRequest have been deprecated in favor of chrome.runtime.sendMessage and chrome.runtime.onMessage respectively. That means, you can still use sendRequest and onRequest but it might be subject to removal in a future version of Chrome
The keyCode for G is 71 rather than 17

Related

How to show Chrome Extension on certain domains?

I'm writing my first Chrome Extension. I've used permission, but I'm seeing my button everywhere.
How can I only show the button on the addresses I'm writing the extension for?
Although the answer from #Sorter works, it is not the best way to solve the problem.
First and foremost, it does not always work. If the page used history.pushState, the page action will disappear and not come back until you trigger the onUpdated or onHighlighted event again Chromium issue 231075.
Secondly, the method is inefficient, because it's triggered for every update of tab state on all pages.
The most efficient and reliable way to get a page action to appear on certain domains is to use the declarativeContent API. This is only available since Chrome 33. Before that, the webNavigation API was the most suitable API. The advantage of these API over the method using the tabs API is that you can safely use event pages, because you can declare URL filters. With these URL filters, the events will only be triggered if you navigate to a page that matches the URL filters. Consequently, your extension/event page will not be activated until really needed (= no wasted RAM or CPU).
Here's a minimal example (background.js) using the webNavigation API:
function onWebNav(details) {
if (details.frameId === 0) {
// Top-level frame
chrome.pageAction.show(details.tabId);
}
}
var filter = {
url: [{
hostEquals: 'example.com'
}]
};
chrome.webNavigation.onCommitted.addListener(onWebNav, filter);
chrome.webNavigation.onHistoryStateUpdated.addListener(onWebNav, filter);
manifest.json:
{
"name": "Name ",
"version": "1",
"manifest_version": 2,
"background": {
"scripts": ["background.js"],
"persistent": false
},
"page_action": {
"default_title": "Only visible on stackoverflow.com"
},
"permissions": [
"webNavigation"
]
}
If you target Chrome 33 and higher, then you can also use the declarativeContent API instead. Simply replace the "webNavigation" permission with "declarativeContent", and use the following background script (background.js):
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: {
hostEquals: 'example.com'
}
})
],
actions: [new chrome.declarativeContent.ShowPageAction()]
}]);
});
});
In both examples, I used a UrlFilter that matches the example.com domain.
Create background.js which checks for updated and highlighted tab.
function checkForValidUrl(tabId, changeInfo, tab) {
// If 'example.com' is the hostname for the tabs url.
var a = document.createElement ('a');
a.href = tab.url;
if (a.hostname == "example.com") {
// ... show the page action.
chrome.pageAction.show(tabId);
}
};
// Listen for any changes to the URL of any tab.
chrome.tabs.onUpdated.addListener(checkForValidUrl);
//For highlighted tab as well
chrome.tabs.onHighlighted.addListener(checkForValidUrl);
Create popup.html and popup.js in the similar manner.
You can use the variables defined in background.js in content scripts (popup.js) with
chrome.extension.getBackgroundPage().variableName
Here's the example extention download link.
For your reference and ease, here's the sample manifest.json file
{
"manifest_version": 2,
"name": "Example Extension",
"version": "1.0",
"background": {
"scripts": ["background.js"]
},
"page_action":{
"default_icon": "images/icon_16.png",
"default_popup": "popup.html",
"default_title": "Title for the extension"
},
"permissions": [
"tabs"
]
}
An Updated Way:
I use the following with great success:
chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
var url = info.url || tab.url;
if(url && url.indexOf('example.com') > -1)
chrome.pageAction.show(tabId);
else
chrome.pageAction.hide(tabId);
});

sendMessage from background script to content script in app fails

UPDATE
From what I can tell, it is impossible to send a message from the background script to the content script using the "sendMessage" function. However there is a horrible workaround,
In your content script's window.onload, send a message to the background script:
chrome.runtime.sendMessage( { action: "messaging", window: "app" }, this.listenForFutureMessages );
Also in the content script, have the following function:
listenForFutureMessages: function(someAction)
{
//Take some action based on the message
//If we want the background script to be able to contact
//us again, we need to give them another callback. This
//is because Chrome only allows one use per callback
chrome.runtime.sendMessage( { action: "messaging", window: "app" }, this.listenForFutureMessages );
},
In the background script, have a listener that does something like this:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse)
{
if ( request.action === "messaging" )
{
//Save the callback for later
this.listeners[ request.window ] = sendResponse;
//Tell chrome we will be using the callback later
return true;
}
}
);
When your background script wants to send the content script a message, simply call it like this:
this.listeners[ "app" ]( { someProperty: "some value" } );
This is a stupid way to do this, but it makes this actually possible. Hope this helps anyone else who needs this functionality.
ORIGINAL
I'm unable to send a message from my background script to a content script. When I try to find the tab id, it tells me I don't have permissions even though my app has that permission. And when I receive a message from the content script, and print out the sender object, it shows tab.id = -1. The API to send a message to a content script requires a tab id!
chrome.tabs.sendMessage(integer tabId, any message, function responseCallback)
The error:
chrome.tabs is not available: You do not have permission to access this API. Ensure that the required permission or manifest property is included in your manifest.json.
Error in event handler for 'undefined': Cannot call method 'sendMessage' of undefined TypeError: Cannot call method 'sendMessage' of undefined
at chrome-extension://panoaieakcofaegcjfbmhndaekfgpijh/scripts/background.js:109:16
at Event.dispatchToListener (event_bindings:356:21)
at Event.dispatch_ (event_bindings:342:27)
at Event.dispatch (event_bindings:362:17)
at miscellaneous_bindings:167:33
at Event.dispatchToListener (event_bindings:356:21)
at Event.dispatch_ (event_bindings:342:27)
at Event.dispatch (event_bindings:362:17)
at Object.chromeHidden.Port.dispatchOnMessage (miscellaneous_bindings:253:22)
So how do I contact my content script? (I have multiple windows and need to be able to contact them individually)
My manifest:
{
"manifest_version": 2,
"name": "App",
"description": "App",
"version": "0.75",
"minimum_chrome_version": "27",
"offline_enabled": true,
"icons":
{
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
},
"app":
{
"background":
{
"scripts":
[
"scripts/background.js"
]
}
},
"permissions":
[
"unlimitedStorage",
"fullscreen",
{
"fileSystem":
[
"write"
]
},
"background",
"<all_urls>",
"tabs"
],
"update_url": "http://192.168.1.121/app.xml"
}
There's not such a thing called "Content scripts" in a Chrome app. Your manifest file looks like a mixture of a Chrome extension. Open chrome://extensions/, enable developer mode, and you would see a warning that the "background" and "tabs" permissions are invalid for a Chrome app.
If you're implementing a Chrome app, just use chrome.runtime.sendMessage and chrome.runtime.onMessage. These messages can be send from and to your event page and the main page. For example:
// event page (aka background page)
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('main.html');
});
// Later, when you want to notify the app window
chrome.runtime.sendMessage(" ... any message ... ");
<!-- main.html -->
<script src="main.js"></script>
// main.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
// Do something with the message
});

Communication between Content Script to background pages, Manifest v2 (Chrome Extension)

I've been trying to communicate from my Content Script to a background page (for XHR), but then, I've been failing to even establish a communication.
Here's a snippet from content_script.js
$('.genericStreamStory').each(function(){
var link = $(this).find('.uiStreamSource a').attr('href');
$(this).find('.uiStreamFooter').append("<span class='a1' style='color:red !important;'> ยท Sample</span>");
document.querySelector('.a1').onclick=function(){
//alert('span clicked');
chrome.extension.sendMessage({method: "getHTML", data: 'hello'});
};//end of anonymous function
});
back.js
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
if (request.method === "getHTML") {
console.log('check.. '+request.data);
}
});
and finally, manifest.json
{
"name": "App1",
"version": "0.1",
"description": "Yay, I'm so useless.",
"content_scripts": [
{
"matches": ["https://*.facebook.com/*"],
"js": [
"/js/external/jquery.js",
"/js/content_script.js"
]
}
],
"background": {
"scripts": ["/js/back.js"]
},
"manifest_version": 2
}
So this extension basically tries to create append a 'Span' after every facebook post.
When I click the Span element, I get the message in the alert box (which I've commented now). Ideally, this action should communicate with my back.js page.
In back.js, I'm logging the message sent by the content script to the console.
But then, I'm literally getting nothing in the console screen!
I've tried the following :
I replaced onMessage & sendMessage with onRequest & sendRequest. Got a PORT Error
Also tried loading an external script from a .js file replacing inline script. - Blank console!
Is there any bug in my code? Where am I making a mistake?

Chrome Extensions & JS Injection Issue - Resources must be listed in the web_accessible_resources manifest

When I inspected the page, script is injected as expected. But in the console I get Denying load of chrome-extension://lkklhmfekbnfjhmcapngedajgkfbmapm/lib/codemirror.js. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.
manifest.json
{
"name":"test",
"description":"Test description",
"version":"1.0",
"manifest_version": 2 ,
"browser_action": {
"default_icon": "icon.png"
},
"content_scripts": [
{
"matches": ["file:///*test*"],
"js": ["test.js"]
}
],
"web_accessible_resources": ["lib/codemirror.js"]
}
test.js
var srcArray = ["lib/codemirror.js"];
function AddScript(value)
{
var s = document.createElement("SCRIPT")
s.src = chrome.extension.getURL(value);
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
}
srcArray.forEach(AddScript);
I cannot figure out what may be causing the issue. Any advice would be appreciated.
I'm not sure, but if you want to insert some scripts to some page, you can use chrome.tabs.executeScript API. That is good way, and you don't care about web_accessible_resources

Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension

I have tried many ways( all documented procedures)to inject script into a specific page upon checking URL at onUpdated.addListener. Finally the below code with 'executescript' seems to work, but not perfectly. I could able to get alerts but can not able to find document elements of the page through getElementById/getElementsByName.
When I inspected the page, script is injected. But in error console I get:
Denying load of chrome-extension://jfeiadiicafjpmaefageabnpamkapdhe/js/Leoscript.js. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.
Manifest.json:
{
"name": "Leo Extension for Job Boards",
"version": "1.6",
"manifest_version": 2,
"content_security_policy": "script-src 'self'; object-src 'self'",
"description": "Leo Extension",
"background": {
"scripts": ["js/Leojshelper.js"],
"persistent": true
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["js/eventPage.js"],
"run_at" : "document_start"
}
],
"icons":{"48":"images/bob48.png", "128":"images/bob128.png"}, //Define any icon sizes and the files that you want to use with them. 48/128 etc.
"browser_action": {
"default_icon": "images/bob.png", // What icon do you want to display on the chrome toolbar
"default_popup": "LeoExtwatch.html" // The page to popup when button clicked.
},
"permissions": [
"tabs", "<all_urls>" // "http://*/*","https://*/*" // Cross Site Access Requests
],
"web_accessible_resources": ["js/LeoScript.js"]
}
I have also given 'web_accessible_resources' permission to the script, but still no success. Code in background script:
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
if (tab.url.indexOf("in.yahoo") !== -1) {
chrome.tabs.update(tabId, { url: "https://login.yahoo.com/config/mail?.intl=us" });
chrome.tabs.executeScript(tabId, {
code: "document.body.appendChild(document.createElement('script')).src='" +
chrome.extension.getURL("js/LeoScript.js") + "';"
}, null);
Code in LeoScript.js, which will be injected into specific page.
$(document).ready(function () {
alert('injected');
document.getElementById('username').value='aaaaaaa';
});
Content Script :eventPage.js which I used to inject script.
var script = document.createElement('script');
script.src = chrome.extension.getURL("js/Leoscript.js");
(document.body || document.head || document.documentElement).appendChild(script);
Please point me at any changes in the above code that will solve the permission issues. Thanks in advance.
UPDATE: Finally figured out your problem. In eventPage.js, you tried to inject js/Leoscript.js, which is NOT whitelisted, instead of js/LeoScript.js (with a capital 'S'), which is whitelisted. Note that URLs are case-sensitive!
chrome.tabs.executeScript(tabId, {file: 'js/LeoScript.js'});
LeoScript.js:
alert('injected');
document.getElementById('username').value='aaaaaaa';
EDIT:
This is working version where combination of web_accessible_resources and Injection is used
manifest.json
{
"name":"Off Screen Tabs Demo",
"description":"This demonstrates Off Screen Tabs API",
"manifest_version":2,
"version":"1",
"permissions":["tabs","<all_urls>"],
"browser_action":{
"default_icon":"screen.png",
"default_popup":"popup.html"
},
"web_accessible_resources": ["js/LeoScript.js"] ,
"permissions":["tabs","<all_urls>"]
}
LeoScript.js
alert("Injected..");
popup.html
<html>
<head>
<script src="popup.js"></script>
</head>
<body>
</body>
</html>
popup.js*
document.addEventListener("DOMContentLoaded",function (){
chrome.tabs.executeScript( {"file": "js/LeoScript.js"});
});
Let me know if you still have problem in getting it running
Many will land up on this page for this error because they have not included their images/web resources in the manifest.json file. The link to the api documentation is helpful, so sharing it: web resource in manifest