优秀的桌面应用应当能深度融入操作系统,让用户在“双击文件”或“右击文件”时就能直接调用你的软件。文件关联和右键菜单扩展是用户感知“原生感”的两个关键特性。Electron 结合 electron-builder 可以在不写任何 C++ 代码的前提下,完成这两件事。
14.5.1 文件关联:双击就打开我的应用
文件关联的本质是向操作系统注册“我能处理哪类文件”。用户双击 .txt 文件,系统启动记事本,这就是文件关联的作用。在 Electron 中,我们只需要在构建配置中声明关联关系,运行时监听文件打开事件即可。
1. 配置 electron-builder
在 package.json 的 build 字段中加入 fileAssociations 数组:
{
"build": {
"fileAssociations": [
{
"ext": "md",
"name": "MyMarkdownEditor",
"description": "Markdown 文件",
"role": "Editor",
"icon": "assets/file-icon.icns"
},
{
"ext": "txt",
"name": "MyTextDocument",
"role": "Editor"
}
]
}
}
ext:关联的扩展名,小写且不要带点,可以同时为同一个扩展名指定多个格式(例如.jpeg和.jpg)。name(macOS 必备):文件类型的内部标识符。description(Windows):在“文件类型”对话框中显示的描述。role:推荐填写Editor或Viewer,影响系统的行为偏好。icon:为关联文件指定图标,macOS 用.icns,Windows 用.ico,放在build/目录下。
真实经验:macOS 的文件关联由
Info.plist控制,electron-builder会自动生成。Windows 方面,安装包(NSIS 或 MSI)会自动向注册表写入HKEY_CLASSES_ROOT\.md和对应程序路径。卸载时会一并清理这些注册项,无需手动处理。
2. 在应用内接收文件路径
当用户双击已关联的文件时,操作系统会启动你的应用并传入文件路径。获取文件路径有两种典型场景:
- 冷启动(应用尚未运行):通过
process.argv在启动时解析。 - 热启动(应用已在运行):macOS 会触发
open-file事件,Windows 则会触发second-instance事件。因此推荐统一监听如下两个事件:
// main.js
const { app, BrowserWindow } = require('electron');
let mainWindow = null;
// 处理 macOS 的“打开文件”事件
app.on('open-file', (event, filePath) => {
event.preventDefault(); // 阻止默认行为
if (mainWindow) {
mainWindow.webContents.send('file-open', filePath);
} else {
// 窗口还未创建,暂存路径,待窗口就绪后再处理
app.pendingFilePath = filePath;
}
});
app.whenReady().then(() => {
mainWindow = new BrowserWindow({ /* ... */ });
// 处理冷启动参数(包括双击文件启动)
const filePath = process.argv.find(arg => arg.endsWith('.md'));
if (filePath) {
mainWindow.webContents.send('file-open', filePath);
} else if (app.pendingFilePath) {
mainWindow.webContents.send('file-open', app.pendingFilePath);
}
delete app.pendingFilePath;
});
确保单实例:为了避免多个窗口同时打开不同文件,应限制应用只运行一个实例:
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
} else {
app.on('second-instance', (event, argv) => {
// Windows / Linux 下,当用户双击另一个文件时,会走到这里
const filePath = argv.find(arg => arg.endsWith('.md'));
if (mainWindow) {
// 窗口可能已最小化,先还原显示
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.focus();
mainWindow.webContents.send('file-open', filePath);
}
});
}
这样,无论应用是否正在运行,都能可靠地接住用户双击的文件。
14.5.2 右键菜单:在资源管理器中集成应用入口
Windows 资源管理器右键菜单(Shell 扩展)可以让用户直接对文件执行“用我的应用打开”“转换为 PDF”等操作。Electron 自身不提供注册右键菜单的 API,但可以通过安装包脚本向系统注册表写入相应条目。
1. 通过 NSIS 脚本注册右键菜单
electron-builder 默认使用 NSIS 制作 Windows 安装程序,我们可以在 build 配置中注入自定义的 NSIS 脚本:
{
"build": {
"nsis": {
"include": "build/installer.nsh"
}
}
}
新建 build/installer.nsh,内容如下:
!macro customInstall
; 注册右键菜单:对所有 .md 文件添加“用 MyApp 打开”选项
WriteRegStr HKCR ".md" "" "MyApp.md"
WriteRegStr HKCR "MyApp.md" "" "Markdown 文档"
WriteRegStr HKCR "MyApp.md\shell\open" "" "用 MyApp 打开"
WriteRegStr HKCR "MyApp.md\shell\open\command" "" '"$INSTDIR\MyApp.exe" "%1"'
; 可选:在“发送到”菜单也添加一项
CreateDirectory "$SMPROGRAMS\SendTo"
CreateShortCut "$SMPROGRAMS\SendTo\MyApp.lnk" "$INSTDIR\MyApp.exe"
!macroend
!macro customUninstall
; 卸载时清理注册表
DeleteRegKey HKCR ".md"
DeleteRegKey HKCR "MyApp.md"
; 删除发送到快捷方式
Delete "$SMPROGRAMS\SendTo\MyApp.lnk"
!macroend
WriteRegStr将关联信息写入HKEY_CLASSES_ROOT,这是 Windows 文件关联和右键菜单的标准位置。"$INSTDIR\MyApp.exe" "%1"中的%1会被实际文件路径替换,等同于调用MyApp.exe "C:\Users\...\note.md"。- 卸载宏
customUninstall确保用户删除应用后系统恢复原状。
运行效果:用户在 .md 文件上右键,菜单中会出现“用 MyApp 打开”,点击即启动应用并打开所选文件。
无需管理员权限:上述操作只需标准用户权限即可写入
HKEY_CURRENT_USER\Software\Classes(如果你担心权限问题,可以把HKCR改为HKCU\Software\Classes,效果类似但仅限于当前用户)。
2. 使用更灵活的 Electron API(运行时注册)
如果不想动安装脚本,也可以在主进程启动时用 child_process 调用 reg 命令注册,但需要注意路径的可变性和权限问题,一般不推荐长住逻辑,更多用于便携版软件:
const { exec } = require('child_process');
function registerFileContextMenu() {
const appPath = process.execPath; // 当前运行的可执行文件
const commands = [
`reg add "HKCU\\Software\\Classes\\*\\shell\\MyApp" /ve /d "用 MyApp 打开" /f`,
`reg add "HKCU\\Software\\Classes\\*\\shell\\MyApp\\command" /ve /d "\\"${appPath}\\" \\"%1\\"" /f`
];
commands.forEach(cmd => {
exec(cmd, (err) => {
if (err) console.error('右键菜单注册失败:', err);
});
});
}
注意:这种方法不会在卸载时自动清理,用户需要手动在注册表中删除,因此更建议随安装包处理。
14.5.3 跨平台差异与最佳实践
- macOS:没有传统意义上的右键菜单扩展,但可以通过创建系统服务(Service)实现类似效果。不过这对 Electron 应用而言开发成本较高,通常不推荐。文件关联已经是 macOS 上最主流的集成方式。
- Linux:各桌面环境差异较大,文件关联一般通过
.desktop文件中的MimeType字段完成,electron-builder会自动生成,无需额外配置右键菜单。如需特定右键动作,需编写 Nautilus 或 Thunar 扩展,这类扩展通常用原生代码实现,Electron 层面很少介入。 - 调试注意:开发环境下,Windows 的文件关联可能指向了
electron.exe而非最终的打包程序。建议用好打包后的安装版测试右键菜单功能,避免路径错误导致“找不到应用程序”。
最后,无论是右键菜单还是文件关联,都遵循同一个原则:安装时建立约定,运行时接收参数。你只需在主进程中稳妥地监听文件打开事件,就能为用户提供“点击即开”的流畅体验,让 Electron 应用真正融入操作系统的日常使用。