简体   繁体   中英

How to register a url protocol handler in Node.js

I am developing a command line node module and would like to be able to launch it via links on a website.

I want to register a custom protocol my-module:// such that links would have the following format: my-module://action:some-action and clicking on them would start the node package.

If there isn't a node API for this (I'm sure there won't be) then is there a way I can do it from node by invoking system commands?

It must work on Windows, Linux, and MacOS.

Its an interesting idea. I don't think there is currently a cross platform node.js solution out there. I did come across this thread of people asking for the same thing:

https://github.com/rogerwang/node-webkit/issues/951

Electron now supports it with the app.setAsDefaultProtocolClient API ( since v0.37.4 ) for macOS and Windows.

It wouldn't be terribly difficult to write the library to do this.

:

On the windows side you'd have to register the app as the application that handles that URI scheme.

You'll need to set up a registry entry for your application:

HKEY_CLASSES_ROOT
   alert
      (Default) = "URL:Alert Protocol"
      URL Protocol = ""
      DefaultIcon
         (Default) = "alert.exe,1"
      shell
         open
            command
               (Default) = "C:\Program Files\Alert\alert.exe" "%1"

Then, when your application is run by windows, you should be able to see the arguments in process.argv[] . Make sure that you launch a shell to run node, not just your application directly.

Original MSDN article

Note this requires administrator privileges and sets the handler system-wide. To do it per user, you can use HKEY_CURRENT_USER\\Software\\Classes instead, as the Electron's implementation does it .

The cited "OS X" article in the github comment is actually for iOS. I'd look at the following programming guide for info on registering an application to handle a URL scheme:

Apple Dev Documentation

In summary, you'll need to create a launch service and populate the .plist file with CFBundleURLTypes , this field is an array and should be populated with just the protocol name ie http

The following Super User Question has a better solution, but is a per user setting.

"The file you seek is ~/Library/Preferences/com.apple.LaunchServices.plist.

It holds an array called LSHandlers, and the Dictionary children that define an LSHandlerURLScheme can be modified accordingly with the LSHandlerRole."

From what I can tell, there are several ways to accomplish this in Linux (surprise?)

Gnome has a tool that will let you register a url handler w3 archives

gconftool-2 -t string -s /desktop/gnome/url-handlers/tel/command "bin/vonage-call %s"
gconftool-2 -s /desktop/gnome/url-handlers/tel/needs_terminal false -t bool
gconftool-2 -t bool -s /desktop/gnome/url-handlers/tel/enabled true

Some of the lighter weight managers look like they allow you to create fake mime types and register them as URI Protocol handlers.

"Fake mime-types are created for URIs with various scheme like this: application/x-xdg-protocol- Applications supporting specific URI protocol can add the fake mime-type to their MimeType key in their desktop entry files. So it's easy to find out all applications installed on the system supporting a URI scheme by looking in mimeinfo.cache file. Again defaults.list file can be used to specify a default program for speficied URI type." wiki.lxde.org

KDE also supports their own method of handling URL Protocol Handlers:

Create a file: $KDEDIR/share/services/your.protocol and populate it with relevant data:

[Protocol]
exec=/path/to/player "%u"
protocol=lastfm
input=none
output=none
helper=true
listing=
reading=false
writing=false
makedir=false
deleting=false

from last.fm forums of all places

Hope that helps.

Here's how I did on Mac OS with an application NW.js :

  1. Open the app /Applications/Utilities/Script Editor

    type the following code in the editor

    on open location this_URL do shell script "/Applications/X.app/Contents/MacOS/x '" & this_URL & "'" end open location

    Replace X by the name of your App.

    Save the script as an Application Bundle anywhere

  2. Go to the script, right click then ' Show Package Contents ' then edit Contents/info.plist

    Add these lines at the end of the file, just before </dict></plist> :

     <key>CFBundleIdentifier</key> <string>com.mycompany.AppleScript.AppName</string> <!-- edit here --> <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLName</key> <string>AppName</string> <!-- edit here --> <key>CFBundleURLSchemes</key> <array> <string>myurlscheme</string> <!-- your url scheme here --> </array> </dict> </array>
  3. You can now open a link starting with myurlscheme: and see your app is opening!

Edit :

Looks like the module has changed the registration process for good:

const path = require('path');

const ProtocolRegistry = require('protocol-registry');

console.log('Registering...');
// Registers the Protocol
ProtocolRegistry.register({
    protocol: 'testproto', // sets protocol for your command , testproto://**
    command: `node ${path.join(__dirname, './tester.js')} $_URL_`, // this will be executed with a extra argument %url from which it was initiated
    override: true, // Use this with caution as it will destroy all previous Registrations on this protocol
    terminal: true, // Use this to run your command inside a terminal
    script: false
}).then(async () => {
    console.log('Successfully registered');
});

Original Answer :

There is an npm module for this purpose.

link : https://www.npmjs.com/package/protocol-registry

So to do this in nodejs you just need to run the code below:

First Install it

npm i protocol-registry

Then use the code below to register you entry file.

const path = require('path');

const ProtocolRegistry = require('protocol-registry');

console.log('Registering...');
// Registers the Protocol
ProtocolRegistry.register({
    protocol: 'testproto', // set your app for testproto://**
    command: `node ${path.join(__dirname, './index.js')}`, // this will be executed with a extra argument %url from which it was initiated
}).then(async () => {
    console.log('Successfully registered');
});

Then suppose someone opens testproto://test then a new terminal will be launched executing :

node yourapp/index.js testproto://test

First of all creating your own protocol is crazy, don't do that.

It seems all you want to do is to be able to launch you node package from a web-browser. The normal way to launch a external program from a web-browser is to write a browser plugin.

This is how pdf, torrents, iTunes get launched from your browser.

So in summary to do what you want you will have to write a plugin and get your users to install. Not particualy a good idea I would say.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM