name: electron-protocol-handler-setup description: 为Electron应用程序注册和处理跨平台的自定义URL协议(深度链接) allowed-tools: Read, Write, Edit, Bash, Glob, Grep tags: [electron, deep-linking, protocol-handler, url-scheme, desktop]
electron-protocol-handler-setup
为Electron应用程序在Windows、macOS和Linux上注册和处理自定义URL协议(深度链接)。此技能使应用程序能够响应自定义URL方案,如myapp://,以实现深度链接和应用程序间通信。
能力
- 在操作系统级别注册自定义协议处理器
- 在运行的应用程序中处理协议URL
- 为协议注册配置electron-builder
- 实现安全的URL解析和验证
- 处理应用程序启动时的协议激活
- 支持带协议处理的单实例强制执行
- 生成平台特定的注册脚本
- 在开发环境中测试协议处理
输入模式
{
"type": "object",
"properties": {
"projectPath": {
"type": "string",
"description": "Electron项目根目录的路径"
},
"protocols": {
"type": "array",
"items": {
"type": "object",
"properties": {
"scheme": { "type": "string", "description": "协议方案(例如,'myapp')" },
"name": { "type": "string", "description": "人类可读的名称" },
"role": { "enum": ["Viewer", "Editor", "Shell", "None"], "default": "Viewer" }
},
"required": ["scheme", "name"]
}
},
"singleInstance": {
"type": "boolean",
"description": "通过协议中继强制执行单实例",
"default": true
},
"securityOptions": {
"type": "object",
"properties": {
"validateUrls": { "type": "boolean", "default": true },
"allowedHosts": { "type": "array", "items": { "type": "string" } },
"sanitizeParams": { "type": "boolean", "default": true }
}
},
"targetPlatforms": {
"type": "array",
"items": { "enum": ["win32", "darwin", "linux"] }
}
},
"required": ["projectPath", "protocols"]
}
输出模式
{
"type": "object",
"properties": {
"success": { "type": "boolean" },
"files": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": { "type": "string" },
"description": { "type": "string" }
}
}
},
"configuration": {
"type": "object",
"properties": {
"electronBuilder": { "type": "object" },
"packageJson": { "type": "object" }
}
},
"testUrls": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["success"]
}
平台注册
macOS (Info.plist)
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>我的应用程序协议</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Windows (注册表)
// electron-builder.yml
nsis:
perMachine: true
include: "installer.nsh"
; installer.nsh
!macro customInstall
WriteRegStr HKCU "Software\\Classes\\myapp" "" "URL:我的应用程序协议"
WriteRegStr HKCU "Software\\Classes\\myapp" "URL Protocol" ""
WriteRegStr HKCU "Software\\Classes\\myapp\\shell\\open\\command" "" '"$INSTDIR\\MyApp.exe" "%1"'
!macroend
Linux (桌面入口)
[Desktop Entry]
Name=我的应用程序
Exec=/opt/myapp/myapp %u
Type=Application
MimeType=x-scheme-handler/myapp;
实现
协议处理器类
// protocol-handler.js
const { app, shell } = require('electron');
const url = require('url');
class ProtocolHandler {
constructor(mainWindow, options = {}) {
this.mainWindow = mainWindow;
this.scheme = options.scheme || 'myapp';
this.allowedHosts = options.allowedHosts || [];
this.handlers = new Map();
}
register() {
// 设置为默认协议客户端
if (process.defaultApp) {
// 开发环境:使用electron路径注册
app.setAsDefaultProtocolClient(this.scheme, process.execPath, [
path.resolve(process.argv[1])
]);
} else {
// 生产环境
app.setAsDefaultProtocolClient(this.scheme);
}
}
unregister() {
app.removeAsDefaultProtocolClient(this.scheme);
}
handleUrl(protocolUrl) {
if (!this.validateUrl(protocolUrl)) {
console.error('无效的协议URL:', protocolUrl);
return;
}
const parsed = url.parse(protocolUrl, true);
const route = parsed.host || parsed.pathname?.slice(2);
const params = parsed.query;
// 分派给已注册的处理器
const handler = this.handlers.get(route);
if (handler) {
handler(params, parsed);
} else {
console.warn('没有找到路由的处理器:', route);
}
// 聚焦窗口
if (this.mainWindow) {
if (this.mainWindow.isMinimized()) {
this.mainWindow.restore();
}
this.mainWindow.focus();
}
}
validateUrl(protocolUrl) {
try {
const parsed = url.parse(protocolUrl);
// 检查方案
if (parsed.protocol !== `${this.scheme}:`) {
return false;
}
// 如果配置了,检查允许的主机
if (this.allowedHosts.length > 0 && parsed.host) {
if (!this.allowedHosts.includes(parsed.host)) {
return false;
}
}
return true;
} catch {
return false;
}
}
on(route, handler) {
this.handlers.set(route, handler);
}
}
module.exports = ProtocolHandler;
主进程集成
// main.js
const { app } = require('electron');
const ProtocolHandler = require('./protocol-handler');
// 单实例锁
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
} else {
let mainWindow;
let protocolHandler;
app.on('second-instance', (event, commandLine) => {
// 有人试图运行第二个实例
// 处理来自命令行的协议URL(Windows)
const url = commandLine.find(arg => arg.startsWith('myapp://'));
if (url) {
protocolHandler.handleUrl(url);
}
// 聚焦现有窗口
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.focus();
}
});
// macOS:处理协议URL
app.on('open-url', (event, url) => {
event.preventDefault();
if (protocolHandler) {
protocolHandler.handleUrl(url);
}
});
app.whenReady().then(() => {
mainWindow = createWindow();
protocolHandler = new ProtocolHandler(mainWindow, {
scheme: 'myapp',
allowedHosts: ['open', 'auth', 'share']
});
protocolHandler.register();
// 注册路由处理器
protocolHandler.on('open', (params) => {
mainWindow.webContents.send('protocol:open', params);
});
protocolHandler.on('auth', (params) => {
handleOAuthCallback(params);
});
// 如果应用程序启动时带有URL,则处理它
const launchUrl = process.argv.find(arg => arg.startsWith('myapp://'));
if (launchUrl) {
protocolHandler.handleUrl(launchUrl);
}
});
}
electron-builder 配置
# electron-builder.yml
protocols:
- name: "我的应用程序协议"
schemes:
- myapp
role: Viewer
# macOS
mac:
extendInfo:
CFBundleURLTypes:
- CFBundleURLName: "我的应用程序协议"
CFBundleURLSchemes:
- myapp
# Linux
linux:
mimeTypes:
- x-scheme-handler/myapp
desktop:
MimeType: "x-scheme-handler/myapp;"
安全考虑
- 验证所有URL:永远不要信任协议URL的内容
- 白名单路由:只处理已知的路由
- 清理参数:在使用前清理查询参数
- 避免代码执行:永远不要执行协议URL内容
- 记录可疑URL:跟踪无效的协议尝试
// 安全示例
validateParams(params) {
const sanitized = {};
const allowedParams = ['id', 'action', 'token'];
for (const [key, value] of Object.entries(params)) {
if (allowedParams.includes(key)) {
// 清理值
sanitized[key] = String(value).slice(0, 1000);
}
}
return sanitized;
}
测试
# 在macOS上测试
open "myapp://open?file=test.txt"
# 在Windows上测试
start "" "myapp://open?file=test.txt"
# 在Linux上测试
xdg-open "myapp://open?file=test.txt"
相关技能
electron-ipc-security-audit- 安全的协议处理inter-app-communicationprocess - IPC模式electron-builder-config- 打包协议处理器
相关代理
electron-architect- 架构指导desktop-security-auditor- 安全审查