在现代桌面应用开发中,Electron 凭借其跨平台能力和前端友好的特性,受到了越来越多开发者的青睐。但你是否想过,如何让用户从网页上一键启动你本地的 Electron 应用?比如像某些云盘客户端那样,点击网页上的按钮就能直接唤起桌面程序?
本文将手把手教你如何通过自定义协议(URL Scheme)的方式,实现从网页一键唤醒你的 Electron 应用 —— zxjapp://
。
我们希望达到的效果是:
- 在网页中放置一个按钮;
- 用户点击后尝试打开本地安装的 Electron 应用;
- 如果未安装,则提示用户下载;
- 支持 Windows 和 macOS 平台;
- 可扩展:未来可支持传参、深度链接等功能。
二、实现原理概述
要实现网页调起本地应用,核心在于 注册一个自定义的 URL 协议,例如 zxjapp://
,然后让系统知道这个协议应该由我们的 Electron 应用来处理。
Electron 提供了 app.setAsDefaultProtocolClient()
方法,可以让我们轻松地为指定协议设置默认处理程序。
三、具体实现步骤
1. 修改主进程代码(main.js)
首先,在你的 Electron 主进程文件中添加如下代码,用于注册协议和监听请求。
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
enableRemoteModule: false,
nodeIntegration: false
}
});
mainWindow.loadFile('index.html');
// 打开开发者工具(可选)
// mainWindow.webContents.openDevTools();
mainWindow.on('closed', () => {
mainWindow = null;
});
}
// 注册 zxjapp:// 协议
if (require('electron-squirrel-startup')) return;
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.focus();
}
});
app.whenReady().then(() => {
createWindow();
// 设置默认协议处理器
const protocol = require('electron').protocol;
protocol.registerSchemesAsPrivileged([
{ scheme: 'zxjapp', privileges: { bypassCSP: true } }
]);
app.setAsDefaultProtocolClient('zxjapp');
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
}
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
⚠️ 注意:如果你使用的是
electron-builder
打包,确保package.json
中配置了appId
,否则协议可能无法正确注册。
{
"build": {
"appId": "com.zxj.app"
}
}
2. 处理协议调用(可选增强体验)
为了能在应用被调用时做一些事情,比如显示某个页面或传递参数,我们可以监听 open-url
事件:
app.on('will-finish-launching', () => {
app.on('open-url', (event, url) => {
event.preventDefault();
console.log('收到协议调用:', url);
if (mainWindow) {
mainWindow.webContents.send('protocol-url', url);
}
});
});
并在渲染进程中监听这个事件:
const { ipcRenderer } = require('electron');
ipcRenderer.on('protocol-url', (event, url) => {
alert('收到协议地址: ' + url);
// 可以解析并跳转到特定页面
});
3. 网页端添加触发按钮
现在我们在网页中添加一个按钮,点击后尝试打开 zxjapp://
协议。
// 打开绑卡APP
const openDesktopApp = () => {
// 创建一个隐藏的iframe来尝试打开应用
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
// 设置超时时间
const timeout = 2000;
const startTime = Date.now();
// 尝试打开应用
iframe.src = 'runbayun://';
// 监听页面可见性变化
document.addEventListener('visibilitychange', function handler() {
if (document.hidden) {
// 如果页面隐藏,说明应用已安装并成功打开
document.removeEventListener('visibilitychange', handler);
document.body.removeChild(iframe);
return;
}
// 如果超时且页面仍然可见,说明应用未安装
if (Date.now() - startTime > timeout) {
document.removeEventListener('visibilitychange', handler);
document.body.removeChild(iframe);
ElMessage.warning('请先安装润吧云桌面应用');
}
});
};
四、注意事项与常见问题
1. Windows 注册表自动写入
Electron 的 setAsDefaultProtocolClient()
方法会在 Windows 上自动修改注册表项,使 zxjapp://
关联到你的应用。无需手动编辑注册表。
2. macOS 下需要沙盒权限
如果你的应用启用了沙盒(macOS App Sandbox),你需要在 entitlements.plist
文件中添加如下权限:
<key>com.apple.security.protocol-messaging</key>
<true/>