diff --git a/examples.json b/examples.json index 7b3d63c5..10d24b3a 100644 --- a/examples.json +++ b/examples.json @@ -384,7 +384,7 @@ }, { "description": "Example of native messaging, including a Python application and an extension which exchanges messages with it.", - "javascript_apis": ["browserAction.onClicked", "runtime.connectNative"], + "javascript_apis": ["runtime.connectNative"], "name": "native-messaging" }, { diff --git a/native-messaging/README.md b/native-messaging/README.md index 1cb028dc..b3273689 100644 --- a/native-messaging/README.md +++ b/native-messaging/README.md @@ -1,18 +1,37 @@ -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. +# native-messaging -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". +This example demonstrates how to use [native messaging](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_messaging) to exchange messages between an extension and a native application. -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. +## What it does + +The extension, located in the "add-on" folder, provides a popup when the user clicks the extension's action button. When the popup opens, it connects to the native application and listens for messages. When the user clicks the popup's "Send ping" button, the popup sends a message with a payload of "ping" to the native application. The popup displays any messages received from the native application. + +The native application, located in the "app" folder, listens for messages from the extension. When it receives a message, the native application sends a response message with a payload of "pong". The native application is written in Python. + +Best practice for extensions is to avoid opening a long-lived connection to a native application from an event page or background service worker. Doing so keeps the background context and the native application running indefinitely. + +In this example, the popup opens the connection to the native application, so the connection lives only as long as the popup is open. Closing the popup disconnects the port, and the browser shuts down the native application. This ensures that the native application and extension's background context are not kept alive when the extension has nothing to do. + +## What it shows + +This extension example shows how to: + +* Set up an action button with a popup. +* Request permissions to use native messaging. +* Create a manifest file to define the location of a native application. +* Connect to a native application from a popup, so that the connection is scoped to the popup's lifetime. +* Send messages to a native application when the user clicks a button in the popup. +* Receive messages from a native application and display them in the popup. ## Setup -To get this working, there's a little setup to do. +To get this working, you need the correct setup. ### Linux/macOS setup -0. (macOS) Store this extension in a location other than the Desktop, Documents, or Downloads folders in your home directory. macOS has access restrictions on these directories that prevent the Python script from executing as expected. +1. (macOS) Store this extension in a location other than the Desktop, Documents, or Downloads folders in your home directory. macOS has access restrictions on these directories that prevent the Python script from executing as expected. -1. Make sure you have Python 3 installed, and your system's PATH environment variable includes the path to Python. You can check by executing this command: +2. Make sure you have Python 3 installed, and your system's PATH environment variable includes the path to Python. You can check by executing this command: ```bash > which python3 @@ -21,9 +40,9 @@ To get this working, there's a little setup to do. If you don't see the path for Python, install Python 3. See [Using Python on Unix platforms](https://docs.python.org/3/using/unix.html) (for Linux) or [Using Python on a Mac](https://docs.python.org/3/using/mac.html). After making this change, restart Firefox so it picks up the new PATH environment variable. -2. Make sure that the [file permissions](https://en.wikipedia.org/wiki/File_system_permissions) for `app/ping_pong.py` include the `execute` permission. See [this article by RedHat](https://www.redhat.com/sysadmin/linux-file-permissions-explained) for more information. +3. Make sure that the [file permissions](https://en.wikipedia.org/wiki/File_system_permissions) for `app/ping_pong.py` include the `execute` permission. See [this article by Red Hat](https://www.redhat.com/sysadmin/linux-file-permissions-explained) for more information. -3. Update the `"path"` field in `app/ping_pong.json` to be the full path to your `app/ping_pong.py` file. +4. Update the `"path"` field in `app/ping_pong.json` to be the full path to your `app/ping_pong.py` file. For example, if you cloned this repository into `/Users/MDN/webextensions-examples/`, you would update the file like this: @@ -31,7 +50,7 @@ To get this working, there's a little setup to do. "path": "/Users/MDN/webextensions-examples/native-messaging/app/ping_pong.py" ``` -4. Copy `app/ping_pong.json` to the correct location on your computer. There are too many options to list here; see the [Linux](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#linux) and [macOS](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#macos) secitons of [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find the correct location for your OS and personal preference. +5. Copy `app/ping_pong.json` to the correct location on your computer. There are too many options to list here; see the [Linux](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#linux) and [macOS](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#macos) sections of [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find the correct location for your OS and personal preference. ### Windows setup @@ -49,15 +68,13 @@ To get this working, there's a little setup to do. 4. Add a registry key containing the full path of `app\ping_pong.json` on your computer. See [App manifest location](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find details of the registry key to add. -To assist in troubleshooting on Windows, there is a script next to this README file named `check_config_win.py`. Running this in a command shell should help you discover of any problems. +To assist with troubleshooting on Windows, the example includes the `check_config_win.py` script. Running this in a command shell should help you discover any problems. ## Testing the example -First, install the add-on. Visit `about:debugging#/runtime/this-firefox` or, from `about:debugging` click "This Firefox" (or "This Nightly" in the Nightly version of Firefox), click "Load Temporary Add-on", and open the add-on's `manifest.json`. - -Now, open the extension's console using the "Inspect" button. This is where you see communication between the browser and native app. +Install the add-on. Visit `about:debugging#/runtime/this-firefox` or, from `about:debugging`, click "This Firefox" (or "This Nightly" in the Nightly version of Firefox), click "Load Temporary Add-on", and open the add-on's `manifest.json`. -You should see a new browser action icon in the toolbar. Click it. You should see output like this in the console: +Open the extension from its action icon in the toolbar or from the Extensions list. With the popup open, click "Send ping". You should see output like this in the popup: Sending: ping Received: pong diff --git a/native-messaging/add-on/background.js b/native-messaging/add-on/background.js deleted file mode 100644 index de289f31..00000000 --- a/native-messaging/add-on/background.js +++ /dev/null @@ -1,34 +0,0 @@ -/* -On startup, connect to the "ping_pong" app. -*/ -let port = browser.runtime.connectNative("ping_pong"); - -/* -Listen for messages from the app and log them to the console. -*/ -port.onMessage.addListener((response) => { - console.log("Received: " + response); -}); - -/* -Listen for the native messaging port closing. -*/ -port.onDisconnect.addListener((port) => { - if (port.error) { - console.log(`Disconnected due to an error: ${port.error.message}`); - } else { - // The port closed for an unspecified reason. If this occurred right after - // calling `browser.runtime.connectNative()` there may have been a problem - // starting the native messaging client in the first place. - // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#troubleshooting - console.log(`Disconnected`, port); - } -}); - -/* -When the extension's action icon is clicked, send the app a message. -*/ -browser.browserAction.onClicked.addListener(() => { - console.log("Sending: ping"); - port.postMessage("ping"); -}); diff --git a/native-messaging/add-on/manifest.json b/native-messaging/add-on/manifest.json index d0555584..0bd31cc0 100644 --- a/native-messaging/add-on/manifest.json +++ b/native-messaging/add-on/manifest.json @@ -1,7 +1,7 @@ { "description": "Native messaging example add-on", - "manifest_version": 2, + "manifest_version": 3, "name": "Native messaging example", "version": "1.0", "icons": { @@ -10,17 +10,18 @@ "browser_specific_settings": { "gecko": { - "id": "ping_pong@example.org", - "strict_min_version": "50.0" + "id": "native-messaging@mozilla.org", + "data_collection_permissions": { + "required": ["none"] + }, + "strict_min_version": "109.0" } }, - "background": { - "scripts": ["background.js"] - }, - - "browser_action": { - "default_icon": "icons/message.svg" + "action": { + "default_icon": "icons/message.svg", + "default_title": "Native messaging example", + "default_popup": "popup/ping_pong.html" }, "permissions": ["nativeMessaging"] diff --git a/native-messaging/add-on/popup/ping_pong.css b/native-messaging/add-on/popup/ping_pong.css new file mode 100644 index 00000000..1c49cf9b --- /dev/null +++ b/native-messaging/add-on/popup/ping_pong.css @@ -0,0 +1,40 @@ +html, body { + width: 200px; + font: caption; +} + +button { + border: none; + width: 100%; + margin: 3% auto; + padding: 4px; + text-align: center; + font-size: 1.2em; + cursor: pointer; + background-color: #E5F2F2; +} + +button:hover { + background-color: #CFF2F2; +} + +button:disabled { + background-color: #EEEEEE; + color: #767676; + cursor: default; +} + +#messages { + margin: 0; + padding: 0; + list-style: none; +} + +#messages li { + padding: 2px 0; + border-top: 1px solid #E0E0E0; +} + +.error { + color: #A4000F; +} diff --git a/native-messaging/add-on/popup/ping_pong.html b/native-messaging/add-on/popup/ping_pong.html new file mode 100644 index 00000000..172238b0 --- /dev/null +++ b/native-messaging/add-on/popup/ping_pong.html @@ -0,0 +1,15 @@ + + + +
+ + + + + + +