自定义通用 URL 协议实现在浏览器中打开本机任意程序

近期遇到一个场景,需要在浏览器中去打开本地的客户端程序,而且限定不允许使用 IE。所以我实现了一个通用协议。通过这个协议,可以从浏览器去打开本机任意程序并支持传参数。以下是具体内容。

注册协议

将以下文件保存为.reg 文件。导入注册表项,注册协议 ff。你可以将所有的 ff 替换成别的字符串,来实现自己的协议。

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\ff]
"URL Protocol"=""
@="Genaral Call"

[HKEY_CLASSES_ROOT\ff\DefaultIcon]
@=""

[HKEY_CLASSES_ROOT\ff\shell]

[HKEY_CLASSES_ROOT\ff\shell\open]

[HKEY_CLASSES_ROOT\ff\shell\open\command]
@="cmd /v:on /k set m=%1 &&call set n=%%m:ff://=%%&call set n=%%n:,= %% &&start !n! &exit"

用法

在任意浏览器中输入 ff://参数1[,参数2,参数3]

其中参数 1 是要打开的本地程序的完整路径;参数 2,参数 3 是要传递给该本地程序的参数,可选。

例如:

  • 在浏览器中输入 ff://C:/Windows/System32/notepad.exe 打开记事本程序
  • 在浏览器中输入 ff://C:/Windows/System32/notepad.exe,c:/apk_44.conf 打本记事本程序,并且会自动在记事本中打开 c:/apk_44.conf 这个文件

需要特别注意的是:

  • 参数如果是一个路径,那么路径分隔符需要使用 /,而不是 windows 默认的 \
  • 参数如果是一个路径,那么路径里不允许出现空格、中文。如果路径里的确存在空格、中文,可以通过快捷方式间接解决。如:想打开 C:\Program Files\Microsoft VS Code\Code.exe,我们可以创建一个快捷方式指向它,然后去调用这个快捷方式,ff://c:/Code.exe.lnk
  • 参数如果不是一个路径,但有中文,那么被调用的客户端程序接收到参数将是 unicode 格式的,需要客户端支持识别

与前端结合

在前端开发中,只需要像使用 http 协议一样,使用这个自定义协议即可。如

<a href="ff://C:/Windows/System32/notepad.exe">打开记事本</a>

END

使用 JS 检测自定义协议是否存在

之前在《自定义通用 URL 协议实现在浏览器中打开本机任意程序》介绍了通过自定义协议使的浏览器可以调起客户端本地程序的方法,在企业环境的实际应用中,又面临着如何检测自定义的协议是否存在的问题, ie 下可以通过 activex 检测注册表项,chrome 该怎么办呢?有没有通用的解决办法呢?答案是肯定的,甚至有人已经将该功能封装成了通用 JS。具体如下。

  • 访问 github,下载 protocolcheck.js 。引用该 js 后,即可使用以下代码检测
    window.protocolCheck(href,callback)
  • 示例代码
    • example.htmlff 协议是自定义通用 URL 协议实现在浏览器中打开本机任意程序文中示例的协议。你可以替换成任意存在的协议。
    <!DOCTYPE html>
    <html>
    
    <head lang="zh">
        <meta charset="UTF-8">
        <title>自定义协议探测</title>
    </head>
    
    <body>
        <h1>Click one of these labels:</h1>
    
        <div href="unexists:randomstuff">一个不存在的协议</div>
        <div href="ff://C:/Windows/System32/notepad.exe">一个存在的协议</div>
        <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
        <script src="protocolcheck.js"></script>
        <script src="example.js"></script>
    </body>
    
    </html>
    • exampe.js
    $(function () {
        $("div[href]").click(function (event) {
            window.protocolCheck($(this).attr("href"),
                function () {
                    alert("协议未注册");
                });
            event.preventDefault ? event.preventDefault() : event.returnValue = false;
        });
    });
  • 运行效果点击第一个 a 标签时,提示协议未注册,点击第二个 a 标签时,正常打开了记事本程序。
  • END
THE END