Web 网页如何唤起本地 Windows 应用并传递参数(含 Electron 自动注册 + 手动配置指南)
本文基博客 《点击页面按钮唤醒桌面的应用 windows》 扩展整理
在现代企业级系统中,Web 应用常常需要与本地桌面程序协作。例如:
- 点击网页上的"打印"按钮,自动调用专用打印软件;
- 在 OA 系统中点击"打开合同",直接唤起 PDF 阅读器或电子签章工具;
- 第三方 SaaS 平台集成客户已有的 Windows 软件,实现数据互通。
你有没有注意到:飞书、钉钉、百度网盘、腾讯会议等软件,都能通过网页一键唤起本地客户端?
✅ 比如:
- 飞书:
lark://open/message?...- 钉钉:
dingtalk://action=call&user=xxx- 百度网盘:
baidunetdisk://download?file=...
这些能力背后,依赖的是 Windows 的 自定义 URL 协议(Custom URL Scheme) 机制。
Windows 的 自定义 URL 协议(Custom URL Scheme) 是一种系统级机制,允许开发者注册一个以 xxx:// 开头的协议(如 myapp://),并将其关联到本地某个可执行程序。
当用户在浏览器、资源管理器或其他支持 URL 调用的地方点击或访问该协议链接时,Windows 会自动启动对应的应用程序,并将完整的 URL 作为命令行参数传递给它。
本文将从零开始,教你如何:
- 手动注册自定义协议(适合测试或非 Electron 场景);
- 让 Electron 应用在安装时自动注册协议(开箱即用);
- 网页如何安全传参,本地程序如何接收;
- 解答一个关键问题:应用在后台运行和完全未启动,行为有何不同?
一、真实案例:主流软件如何做到"网页唤起本地应用"?
当你在浏览器点击飞书会议链接 lark://meet/12345,系统会立即启动飞书客户端并加入会议。这是因为在你首次安装飞书时,它就悄悄做了以下事情:
- 在 Windows 注册表中注册了
lark协议; - 将该协议绑定到
Feishu.exe的安装路径; - 声明:"今后所有
lark://开头的请求,请交给我处理"。
类似地:
| 软件 | 协议示例 | 用途 |
|---|---|---|
| 钉钉 | dingtalk:// |
发消息、拨号、打开工作台 |
| 百度网盘 | baidunetdisk:// |
下载文件、打开本地目录 |
| 腾讯会议 | zoommtg:// / wemeet:// |
加入会议 |
| 微信(Windows) | weixin:// |
打开聊天(部分版本支持) |
💡 这些软件无需用户手动配置,安装即生效------这正是我们要实现的目标。
二、方案选择:手动注册 vs 自动注册
| 方式 | 适用场景 | 是否需要用户操作 |
|---|---|---|
| 手动修改注册表 | 测试、内部工具、非打包应用 | ✅ 需要 |
| Electron 安装自动注册 | 正式产品、分发给客户 | ❌ 无需 |
下面分别介绍两种方式。
三、方式一:手动配置注册表(详细步骤)
📌 适用于:C++/C#/Python 打包的 exe、临时测试、无安装包的场景
步骤 1:确定你的应用路径
假设你的程序位于:
C:\MyApp\MyApp.exe
步骤 2:打开注册表编辑器
- 按
Win + R,输入regedit,回车。
步骤 3:创建协议项
- 导航到
HKEY_CLASSES_ROOT - 右键 → 新建 → 项,命名为你的协议名(如
myapp) - 在
myapp项内:- 右键 → 新建 → 字符串值 ,名称为
URL Protocol(值留空) - 双击左侧
(默认),设置值为"URL: MyApp Protocol"(可选描述)
- 右键 → 新建 → 字符串值 ,名称为
步骤 4:绑定到应用程序
继续在 myapp 下创建层级:
myapp
└── shell
└── open
└── command
进入 command,双击 (默认),输入:
text
"C:\MyApp\MyApp.exe" "%1"
⚠️ 注意:
- 路径必须用英文双引号包裹;
%1表示完整的 URL(如myapp://action?file=xxx)
步骤 5:验证是否成功
- 按
Win + R,输入myapp://test; - 如果你的程序启动,说明注册成功!
替代方法:使用 .reg 文件一键导入
新建 register_myapp.reg,内容如下:
reg
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\myapp]
@="URL: MyApp Protocol"
"URL Protocol"=""
[HKEY_CLASSES_ROOT\myapp\shell\open\command]
@="\"C:\\MyApp\\MyApp.exe\" \"%1\""
双击运行即可写入注册表。
四、方式二:Electron 应用安装时自动注册协议(推荐)
使用 electron-builder 打包时,只需简单配置,安装程序会自动完成注册。
步骤 1:在 package.json 中声明协议
json
{
"name": "myapp",
"build": {
"appId": "com.example.myapp",
"productName": "MyApp",
"win": {
"target": "nsis"
},
"protocols": [
{
"name": "MyApp Protocol",
"schemes": ["myapp"]
}
]
}
}
步骤 2:主进程监听协议唤起
js
// main.js
const { app } = require('electron');
app.on('open-url', (event, url) => {
event.preventDefault();
handleProtocol(url);
});
// Windows 启动时从 argv 获取
if (process.defaultApp) {
const url = process.argv.find(arg => arg.startsWith('myapp://'));
if (url) handleProtocol(url);
}
function handleProtocol(fullUrl) {
console.log('收到:', fullUrl);
// 解析参数并处理业务逻辑
}
步骤 3:构建安装包
bash
npx electron-builder --win
生成的 Setup.exe 在安装时会自动注册 myapp:// 协议,用户无需任何操作。
五、Web 页面如何唤起应用?(Vue2 示例)
vue
<template>
<button @click="launchApp">打开本地应用</button>
</template>
<script>
export default {
methods: {
launchApp() {
const params = new URLSearchParams({
action: 'print',
filePath: 'C:\\Reports\\Q4.pdf'
});
const url = `myapp://handle?${params.toString()}`;
// myapp://handle?action=print&filePath=C%3A%5CReports%5CQ4.pdf
window.location.href = url;
}
}
}
</script>
🔔 浏览器可能会弹出安全提示:"是否允许打开 MyApp?"------这是正常现象。
六、关键问题:应用在后台运行 vs 完全未启动,有区别吗?
有!而且行为完全不同。
| 场景 | 系统行为 | Electron 如何处理 |
|---|---|---|
| 应用未启动 | Windows 会启动新进程,并将 URL 作为命令行参数传入(process.argv[1]) |
在 app.whenReady() 中解析 argv |
| 应用已在后台运行 | Windows 会向已有进程 发送 WM_COPYDATA 或触发 second-instance 事件 |
监听 app.on('second-instance', ...) |
Electron 推荐写法(兼容两种情况):
js
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
} else {
app.on('second-instance', (event, argv) => {
const url = argv.find(a => a.startsWith('myapp://'));
if (url) handleProtocol(url);
});
app.whenReady().then(() => {
createWindow();
// 首次启动检查
const url = process.argv.find(a => a.startsWith('myapp://'));
if (url) handleProtocol(url);
});
}
✅ 这样无论应用是否已运行,都能正确接收参数。
七、重要提醒:Web 无法知道本地应用是否已安装或运行!
这是一个常见误区:
❌ "网页能否检测用户是否安装了 MyApp?"
答案:不能。
出于安全限制,浏览器无法探测本地文件系统或进程列表。你只能:
- 尝试唤起协议;
- 如果失败(如弹出"找不到应用"错误),引导用户去下载安装;
- 或通过其他间接方式(如本地 HTTP 服务、WebSocket 心跳)判断,但这需要额外开发。
因此,良好的用户体验应包含 fallback 机制:
js
function launchApp() {
const url = 'myapp://test';
window.location.href = url;
// 3 秒后若未跳转,说明可能未安装
setTimeout(() => {
if (!document.hidden) {
alert('未检测到 MyApp,请先安装');
window.open('https://example.com/download');
}
}, 3000);
}
八、总结
| 能力 | 实现方式 |
|---|---|
| ✅ 网页唤起本地应用 | 自定义 URL 协议(myapp://) |
| ✅ 安装时自动注册 | electron-builder + protocols 配置 |
| ✅ 手动注册(测试用) | 修改 HKEY_CLASSES_ROOT\myapp |
| ✅ 传参与接收 | URL 查询参数 + Electron argv / open-url |
| ✅ 兼容后台/未启动 | 使用 requestSingleInstanceLock + second-instance |
| ❌ 检测是否安装 | 浏览器无法实现,需 fallback 引导 |
通过本文方法,你可以像飞书、钉钉一样,打造"网页一键唤起本地应用"的无缝体验。
🎯 适用场景:政企系统集成、医疗设备控制、金融终端、离线任务调度等。
现在,轮到你的应用登场了!🚀