I created an extension that uses native messaging to a host.
The manifest.json of the extension is:
{
"manifest_version": 2,
"version": "1.0",
"name": "Native Messaging Example",
"description": "Send a message to a native application",
"permissions": [
"nativeMessaging"
],
"browser_action": {
"default_popup": "popup.html"
}
}
The popup.html:
<html>
<head>
<script src="./main.js"></script>
</head>
<body>
<button id="buttonToPress">Press</button>
</body>
</html>
The main.js file:
var port = null;
function connect() {
port = chrome.runtime.connectNative('com.google.chrome.example.echo');
port.onMessage.addListener(function(message) {
alert(message);
port.disconnect();
});
port.onDisconnect.addListener(function() {
port = null;
alert(chrome.runtime.lastError.message);
});
var message = {
'filePath': 'C:\\Users\\username\\Desktop\\themes\\Wallpaper\\Architecture\\img13.jpg'
};
port.postMessage(message);
}
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('buttonToPress').addEventListener('click', connect);
});
I have a native application abc.exe.
The native application manifest.json:
{
"name": "com.google.chrome.example.echo",
"description": "Chrome Native Messaging API Example Host",
"path": "./abc.exe",
"type": "stdio",
"allowed_origins": [
"chrome-extensions://fegpbklgdffjmfjmhknpmgepbddbcghk/"
]
}
In the registrey, The Default Value of HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.google.chrome.example.echo is C:\Users\username\Desktop\Extension1\NativeApp\manifest.json (This is where the manifest file is physically exists).
The problem is, that each time i run it, it keep saying: 'Specified Native Messaging Host Not Found'... I rechecked my code and it seems to be fine, just like the google's guide of native messaging. The error that logged in the debugger's console is: 'Uncaught Error: Attempting to use a disconnected port object', which i don't know why it keeps happening.
Also, after the chrome.runtime.connectNative, the .exe doesn't start (after seeing in the task manager), and it just seems likes there something that not code-related, but more likely to be in the configuration.
I need some help in figuring it out, so any help would be usefull!
Thanks
notice that chrome extension listed in allowed_origins has to end with /
wrong code (without /):
"allowed_origins": [
"chrome-extension://acajlpgjiolkocfooiankmegidcifefo"
]
correct code:
"allowed_origins": [
"chrome-extension://acajlpgjiolkocfooiankmegidcifefo/"
]
I've managed to work the solution out. I've created the whole pack once again from scratch and set the name of the host application in lowercase. Also i set the key in the registry in 'CURRENT_USER' and it worked well. I guess that maybe the host name should be in lowercase but other than this I don't know where I went wrong. Thanks alot guys for the help!!! I Appreciate it!
I'm not sure relative paths work for Native Host manifests.
In any case, if you compare with the example in the docs, you're using the wrong kind of slash.
Related
When the button is pressed, I want to get the URL from the current tab and pass it as an argument to the script.
I know that I have to use browser.browserAction.onClicked.addListener() but I have not found an API for the call to the command line.
Can anybody tell me if this is possible and if not if there is a workaround?
Edit: Thanks to #wOxxOm who pointed me to Native messaging in the comment I was able to proceed as follows:
I used the example here to create my extension and app manifest.
Extension manifest:
manifest.json
{
"manifest_version": 2,
"name": "test",
"version": "1.0",
"description": "Description",
"icons": {
"48": "icons/test_logo-48.png"
},
"browser_action": {
"default_icon": "icons/test_logo-48.png",
"default_title": "test"
},
"browser_specific_settings": {
"gecko": {
"id": "test#example.org",
"strict_min_version": "50.0"
}
},
"background": {
"scripts": ["background.js"]
},
"permissions": ["nativeMessaging"]
}
App manifest:
native_manifest.json:
{
"name": "test",
"description": "Example host for native messaging",
"path": "C:\\Users\\test\\Documents\\PowerShell\\Scripts\\extension.bat",
"type": "stdio",
"allowed_extensions": [ "test#example.org" ]
}
Note that the path in the native_manifest.json is the path to a Windows .bat file which runs the Powershell script
I created two registry entries:
New-Item -Path HKCU:\SOFTWARE\Mozilla\NativeMessagingHosts\test -Value "C:\\Users\\test\\Documents\\PowerShell\\firefox_extension\\test\\native_manifest.json"
New-Item -Path HKLM:\SOFTWARE\Mozilla\NativeMessagingHosts\test -Value "C:\\Users\\test\\Documents\\PowerShell\\firefox_extension\\test\\native_manifest.json"
These entries point to the location of the App manifest. This is the root folder of the extension where the manifest.json and the background.js is also saved.
The background.js extension script:
/*
On startup, connect to the nhative app.
*/
let port = browser.runtime.connectNative("test");
On a click on the browser action, send the app a message.
*/
browser.browserAction.onClicked.addListener(() => {
console.log("Sending: ping");
port.postMessage("example.txt");
});
The .bat file launching the script:
extension.bat
#echo off
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '.\fire.ps1'"
Powershell test script:
param ($test="C:\Users\test\Documents\PowerShell\firefox_extension\test\default.txt")
get-date | out-file $test
The script works, the test file is created, but with the default parameter path. So far so good, but I cannot figure out how to read the passed message in Powershell from Stdin.
I found an answer here explaining to use the -command - parameter, however I'm already using it to call my script. Another possibility seems to be to use [Console]::In but I'm not sure how.
Can anybody help and provide an example how I can read the passed message from the extension in the powershell script? According to documentation it is passed to stdin.
I'm new to Chrome extension development. I am currently looking to make a Chrome extension to dismiss notifications. I want the extension to be activated once via shortcut keys.
Before looking at the code below, I want to let it be known that the alert does show up... but the Chrome Extensions page shows the error:
"Error in event handler for commands.onCommand: TypeError: Cannot read property 'getAll' of undefined"
on the line:
chrome.notifications.getAll((items) => {
The chrome.notifications object is somehow undefined, so it seems that Chrome thinks that there are no current notifications being displayed...which is strange because there indeed are, as the image shows.
Would anyone please help by shedding some light on this situation?
manifest.json:
{
"name": "ClearAll",
"version": "1.0",
"description": "Clear notifications!",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"commands": {
"clear": {
"suggested_key":{
"default": "Alt+Shift+S"
},
"description": "Executes clear"
}
},
"manifest_version": 2
}
background.js:
chrome.commands.onCommand.addListener(function(command) {
if (command == 'clear') {
alert("testing");
chrome.notifications.getAll((items) => {
if (items)
for (let key in items)
chrome.notifications.clear(key);
});
}
});
Error:
You might already have figured this out, but for anyone who stumbles upon this question in the future: it's not possible to write an extension that dismisses all notifications on Chrome because it is not possible for any extension to get access to a user's browser-wide notifications; the notifications permission in the manifest.json lets you create and clear notifications created by your extension. Indeed, it would be a privacy violation if any extension was allowed to do this!
From https://developer.chrome.com/apps/notifications#method-getAll,
Retrieves all the notifications of this app or extension (emphasis mine.)
You need to add the notifications permission to your manifest
{
"name": "ClearAll",
"permissions": ["notifications"],
.......
}
I was trying to create a Mozilla Firefox URL redirection addon however when I created it myself using the code on the mozilla firefox page about OnBeforeRequest url redirection, the addon didn't work. So I decided to copy and paste the code from the Mozilla website guide to see if I wrote the code wrong, however the same thing happens. It cancels the requests correctly however whenever I try redirecting urls using the redirectUrl option, it doesn't work
My code is as follows:
manifest.json
{
"description": "Demonstrating webRequests",
"manifest_version": 2,
"name": "webRequest-demo",
"version": "1.0",
"applications": {
"gecko": {
"id": "#addontest"
}
},
"permissions": [
"webRequest", "webRequestBlocking"
],
"background": {
"scripts": ["main.js"]
}
}
main.js
var pattern = "https://mdn.mozillademos.org/*";
function redirect(requestDetails) {
console.log("Redirecting: " + requestDetails.url);
return {
redirectUrl: "https://38.media.tumblr.com/tumblr_ldbj01lZiP1qe0eclo1_500.gif"
// cancel:true
};
}
browser.webRequest.onBeforeRequest.addListener(
redirect,
{urls:[pattern], types:["image"]},
["blocking"]
);
In the main.js, if I were to comment out the
redirectUrl: "https://38.media.tumblr.com/tumblr_ldbj01lZiP1qe0eclo1_500.gif"
and uncomment the following line:
cancel:true
the code works correctly and the requests are canceled, however its just whenever I try to redirect it, it stops working.
Can anyone help please? It's been bugging me for a few days now and I just can't seem to find anything to fix it. There's no errors or anything in the firefox console (CTRL + SHIFT + J) or in the firebug console
I made a working Chrome extension that is not packaged and is just a directory on my computer. I found out that I should be able to port this to Firefox rather easily.
I followed the "Porting a Google Chrome extension" guide on MDN and found that my manifest file is perfect.
I then followed the instructions on how to perform "Temporary Installation in Firefox" of the extension.
However, when I click on any file inside the directory, nothing happens. The extension doesn't load. Any advice? I know the extension works in Chrome fine and loads without error.
manifest.json:
{
"manifest_version": 2,
"name": "ER",
"description": "P",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"scripts": [ "background.js" ]
},
"content_scripts": [
{
"matches": [ "SiteIwant" ],
"js": [ "ChromeFormFill.js" ],
"run_at": "document_idle"
}
],
"permissions": [
"*://*/*",
"cookies",
"activeTab",
"tabs",
"https://ajax.googleapis.com/"
],
"externally_connectable": {
"matches": ["SiteIwant"]
}
}
ChromeFormFill.js:
// JavaScript source c
console.log("inside content");
console.log(chrome.runtime.id);
document.getElementById("ID").value = chrome.runtime.id.toString();
Background.js
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.data === "info") {
console.log("Recieving Info");
return true;
}
});
chrome.tabs.create(
{
url: 'myUrl'
active: true
}, function (tab) {
chrome.tabs.executeScript(tab.id, { file: 'Run.js', runAt: "document_idle" });
});
Run.js will just alert('hi').
It just won't do anything when I try to load it on Firefox; nothing will happen.
Issues:
In manifest.json:
externally_connectable is not supported:1
Firefox does not support externally_connectable. You can follow bug 1319168 for more information. There is, currently, no expected time when this will be implemented.
You will need to communicate between the code on your site and the WebExtension using a different method. The way to do so is to inject a content script and communicate between the site's code and the content script. The common ways to do this are CustomEvent() or window.postMessage(). My preference is CustomEvent().
Using window.postMessage() is like yelling your message outside and hoping that either nobody else is listening, or that they know that they should ignore the message. Other people's code that is also using window.postMessage() must have been written to ignore your messages. You have to write your code to ignore any potential messages from other code. If either of those were not done, then your code or the other code can malfunction.
Using CustomEvent() is like talking directly to someone in a room. Other people could be listening, but they need to know about the room's existence in order to do so, and specifically choose to be listening to your conversation. Custom events are only received by code that is listening for the event type which you have specified, which could be any valid identifier you choose. This makes it much less likely that interference will happen by mistake. You can also choose to use multiple different event types to mean different things, or just use one event type and have a defined format for your messages that allows discriminating between any possible types of messages you need.
matches value needs to be valid (assumed to be intentionally redacted):
You have two lines (one with a trailing ,, one without; both syntactically correct):
"matches": ["SiteIwant"]
"SiteIwant" needs to be a valid match pattern. I'm assuming that this was changed away from something valid to obfuscate the site that you are working with. I used:
"matches": [ "*://*.mozilla.org/*" ]
In Background.js:
The lines:
url: 'myUrl'
active: true
need to be:
url: 'myUrl',
active: true
[Note the , after 'myUrl'.] In addition, myUrl needs to be a valid URL. I used:
url: 'http://www.mozilla.org/',
A Firefox 48 bug (now long fixed):
Your line:
chrome.tabs.executeScript(tab.id, { file: 'Run.js', runAt: "document_idle" });
In Firefox 48 this line is executed prior to the tab being available. This is a bug. It is fixed in Firefox Developer Edition and Nightly. You will need one of those to test/continue development.
Issues in ChromeFormFill.js:
Another Firefox 48 bug (now long fixed):
chrome.runtime.id is undefined. This is fixed in Developer Edition and Nightly.
Potential content script issue:
I'm going to assume your HTML has an element with an ID = 'ID'. If not, your document.getElementById("ID") will be null. You don't check to see if the returned value is valid.
Running your example code
Once all those errors were resolved, and running under Firefox Nightly, or Developer Edition, it worked fine. However, you didn't have anything that relied on being externally_connectable, which won't function.
agaggi noticed that I had forgotten to include this issue in the original version of my answer.
I'm trying to access serial/usb ports via chrome plugins/extensions. Im following the documents from chrome usb && chrome serial , when i started my plugin it throws
"Uncaught TypeError: Cannot read property 'getDevices' of undefined"
i also tried the sample codes from google chrome sample but experienced the same problem, basically chrome.usb / chrome.serial is undefined.
Any suggestions to put me right direction is appreciated. Thanks !
Im attaching my sample codes
popup.html
<!DOCTYPE html>
<html>
<body style="width: 300px">
Open this page and then
<button id="clickme">click me</button>
<script type="text/javascript" src="popup.js"></script>
</body>
</html>
popup.js
function readPorts() {
console.log("Reading ports . . . . . ")
chrome.usb.getDevices(function(devices) {
console.warn('chrome.usb.getDevices error: ' +
chrome.runtime.lastError.message);
for (var i = 0; i < devices.length; i++) {
console.log('Device : ' + devices[i].path + '"===' + devices[i].path + '=====');
}
});
}
document.getElementById('clickme').addEventListener('click', readPorts);
manifest
{
"manifest_version": 2,
"name": "Getting started example",
"description": "This extension will read the com ports from your machine",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html",
"default_title": "Read com ports!"
},
"content_scripts": [
{
"matches": ["http://*/*","https://*/*"],
"js": ["myscript.js"]
}
],
"permissions": [
"serial",
"usb"
]
}
Only Chrome Apps (not Chrome Extensions) have access to the hardware. Check the steps for creating a Chrome App: https://developer.chrome.com/apps/first_app
Both of those APIs are limited to Chrome Apps. Your manifest specifies an extension.
Chrome Extensions have an entirely different set of APIs. They overlap, but one is not a superset of another.
If you want a content script (read: interact with the browser itself), it must be an extension. If you want USB/Serial API, it must be an App.
You must either rethink how to interact with the browser (Apps have some ways to expose themselves to pages) or make both and let them talk to each other.