diff --git a/native-messaging/README.md b/native-messaging/README.md new file mode 100644 index 0000000..b2c5999 --- /dev/null +++ b/native-messaging/README.md @@ -0,0 +1,33 @@ +This is a very simple example of how to use [native messaging](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging) to exchange messages between a WebExtension and a native application. + +The WebExtension, which can be found under "add-on", connects to the native application and listens to messages from it. It then sends a message to the native application when the user clicks on the WebExtension's browser action. The message payload is just "ping". + +The native application, which can be found under "app", listens for messages from the WebExtension. When it receives a message, the native application sends a response message whose payload is just "pong". The native application is written in Python. + +## Setup ## + +To get this working, there's a little setup to do. + +### Mac OS/Linux setup ### + +1. Check that the [file permissions](https://en.wikipedia.org/wiki/File_system_permissions) for "ping_pong.py" include the `execute` permission. +2. Edit the "path" property of "ping_pong.json" to point to the location of "ping_pong.py" on your computer. +3. copy "ping_pong.json" to the correct location on your computer. See [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging#App_manifest_location) to find the correct location for your OS. + +### Windows setup ### + +1. Check you have Python installed, and that your system's PATH environment variable includes the path to Python. See [Using Python on Windows](https://docs.python.org/2/using/windows.html). You'll need to restart the web browser after making this change, or the browser won't pick up the new environment variable. +2. Edit the "path" property of "ping_pong.json" to point to the location of "ping_pong_win.bat" on your computer. Note that you'll need to escape the Windows directory separator, like this: `"path": "C:\\Users\\MDN\\native-messaging\\app\\ping_pong_win.bat"`. +3. Edit "ping_pong_win.bat" to refer to the location of "ping_pong.py" on your computer. +4. Add a registry key containing the path to "ping_pong.json" on your computer. See [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging#App_manifest_location) to find details of the registry key to add. + +## Testing the example ## + +Then just install the add-on as usual, by visiting about:debugging, clicking "Load Temporary Add-on", and selecting the add-on's "manifest.json". + +You should see a new browser action icon in the toolbar. Open the console ("Tools/Web Developer/Browser Console" in Firefox), and click the browser action icon. You should see output like this in the console: + + Sending: ping + Received: pong + +If you don't see this output, see the [Troubleshooting guide](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging#Troubleshooting) for ideas. diff --git a/native-messaging/add-on/background.js b/native-messaging/add-on/background.js new file mode 100644 index 0000000..4cdabef --- /dev/null +++ b/native-messaging/add-on/background.js @@ -0,0 +1,19 @@ +/* +On startup, connect to the "ping_pong" app. +*/ +var port = browser.runtime.connectNative("ping_pong"); + +/* +Listen for messages from the app. +*/ +port.onMessage.addListener((response) => { + console.log("Received: " + response); +}); + +/* +On a click on the browser action, send the app a message. +*/ +browser.browserAction.onClicked.addListener(() => { + console.log("Sending: ping"); + port.postMessage("ping"); +}); diff --git a/native-messaging/add-on/icons/LICENSE b/native-messaging/add-on/icons/LICENSE new file mode 100644 index 0000000..c4e7bdc --- /dev/null +++ b/native-messaging/add-on/icons/LICENSE @@ -0,0 +1 @@ +The icon used here is taken from the "Miscellany Web icons" set by Maria & Guillem (https://www.iconfinder.com/andromina), and is used under the Creative Commons (Attribution 3.0 Unported) license. diff --git a/native-messaging/add-on/icons/message.svg b/native-messaging/add-on/icons/message.svg new file mode 100644 index 0000000..7ee68e2 --- /dev/null +++ b/native-messaging/add-on/icons/message.svg @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/native-messaging/add-on/manifest.json b/native-messaging/add-on/manifest.json new file mode 100644 index 0000000..bd3ba1f --- /dev/null +++ b/native-messaging/add-on/manifest.json @@ -0,0 +1,28 @@ +{ + + "description": "Native messaging example add-on", + "manifest_version": 2, + "name": "Native messaging example", + "version": "1.0", + "icons": { + "48": "icons/message.svg" + }, + + "applications": { + "gecko": { + "id": "ping_pong@example.org", + "strict_min_version": "50.0" + } + }, + + "background": { + "scripts": ["background.js"] + }, + + "browser_action": { + "default_icon": "icons/message.svg" + }, + + "permissions": ["nativeMessaging"] + +} diff --git a/native-messaging/app/ping_pong.json b/native-messaging/app/ping_pong.json new file mode 100644 index 0000000..a257b18 --- /dev/null +++ b/native-messaging/app/ping_pong.json @@ -0,0 +1,7 @@ +{ + "name": "ping_pong", + "description": "Example host for native messaging", + "path": "/path/to/native-messaging/app/ping_pong.py", + "type": "stdio", + "allowed_extensions": [ "ping_pong@example.org" ] +} diff --git a/native-messaging/app/ping_pong.py b/native-messaging/app/ping_pong.py new file mode 100755 index 0000000..ce06c7e --- /dev/null +++ b/native-messaging/app/ping_pong.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +import sys, json, struct + +# Read a message from stdin and decode it. +def getMessage(): + rawLength = sys.stdin.read(4) + if len(rawLength) == 0: + sys.exit(0) + messageLength = struct.unpack('@I', rawLength)[0] + message = sys.stdin.read(messageLength) + return json.loads(message) + +# Encode a message for transmission, +# given its content. +def encodeMessage(messageContent): + encodedContent = json.dumps(messageContent) + encodedLength = struct.pack('@I', len(encodedContent)) + return {'length': encodedLength, 'content': encodedContent} + +# Send an encoded message to stdout +def sendMessage(encodedMessage): + sys.stdout.write(encodedMessage['length']) + sys.stdout.write(encodedMessage['content']) + sys.stdout.flush() + +while True: + receivedMessage = getMessage() + if (receivedMessage == "ping"): + sendMessage(encodeMessage("pong")) diff --git a/native-messaging/app/ping_pong_win.bat b/native-messaging/app/ping_pong_win.bat new file mode 100644 index 0000000..aac2019 --- /dev/null +++ b/native-messaging/app/ping_pong_win.bat @@ -0,0 +1,3 @@ +@echo off + +call python C:\path\to\ping_pong.py