Electron 自定义协议、资源加载与深链接
🎯 引言
开发时页面通常来自 http://localhost,打包后则来自本地文件。路径变化是 Electron 初学者经常遇到的问题。本篇先掌握判断加载方式的方法,再认识自定义协议的用途。
🧱 开发和生产的加载差异
const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL);
if (isDevelopment) {
win.loadURL(process.env.VITE_DEV_SERVER_URL);
} else {
win.loadFile(path.join(__dirname, '../dist/index.html'));
}
开发环境需要服务器提供热更新,生产环境则需要把构建目录一起放进应用包。不要把开发服务器地址写死成生产环境配置。
🧰 为什么要使用自定义协议
大多数 Electron 项目不需要自定义协议,使用 loadFile() 加载 index.html 就可以了。
只有当应用有很多内部页面、图片和脚本,或者希望所有内部资源都使用统一地址时,自定义协议才有价值。它的作用可以简单理解为:给应用内部资源起一个统一的地址,并由主进程决定这个地址能打开什么文件。
例如,应用不直接使用某个具体的本地文件路径,而是使用:
app://local/index.html
主进程收到这个地址后,再把它对应到应用包里的 dist/index.html:
const { app, BrowserWindow, net, protocol } = require('electron/main');
const path = require('node:path');
const { pathToFileURL } = require('node:url');
app.whenReady().then(async () => {
protocol.handle('app', async (request) => {
const url = new URL(request.url);
if (url.pathname !== '/index.html') {
return new Response('Not found', { status: 404 });
}
const filePath = path.join(__dirname, '../dist/index.html');
return net.fetch(pathToFileURL(filePath).toString());
});
const win = new BrowserWindow({
width: 960,
height: 640,
});
await win.loadURL('app://local/index.html');
});
这段代码的过程是:
- 窗口请求
app://local/index.html。 protocol.handle('app', ...)接收到这个请求。- 主进程只允许访问
index.html,并把它映射到dist/index.html。 - 找不到的路径返回 404,不会读取任意本地文件。
初学项目先使用 loadFile() 即可。只有确实需要统一管理内部资源时,再考虑自定义协议;它不是必须配置。
🔗 深链接有什么用
应用内部的普通链接,例如 Vue Router 的 /project/123,直接在当前窗口跳转就可以了,不需要深链接。
深链接解决的是另一个问题:用户在应用外部点击一个链接时,能不能打开桌面应用,并直接定位到应用里的指定内容。
这个链接可能来自浏览器地址栏、邮件、系统通知或其他应用。例如:
electron-course://project/123
用户点击这个链接后,操作系统会寻找注册了 electron-course 协议的 Electron 应用,启动应用,并把 project/123 交给它处理。应用收到后,就可以打开项目 123。
深链接适合这些场景:
- 邮件中有项目链接,点击后直接打开桌面应用里的项目。
- 浏览器页面提供“在桌面应用中打开”按钮。
- 系统通知中带有任务链接,点击后直接定位到某条任务。
如果你的应用只处理窗口内部的普通页面跳转,不需要从浏览器、邮件或通知打开指定内容,就不需要实现深链接。
主进程拿到深链接后,通常只做三件事:解析链接、检查参数、通知当前窗口显示对应内容。
function handleDeepLink(rawUrl) {
const url = new URL(rawUrl);
if (url.protocol !== 'electron-course:') {
return;
}
const projectId = url.pathname.slice(1);
if (!/^\d+$/.test(projectId)) {
return;
}
mainWindow.webContents.send('project:open', projectId);
}
electron-course: 是应用自己注册的协议,project/123 表示要打开的内容。示例中的正则检查是为了避免把任意文字都当成项目编号。
真正接入时,还需要把这个协议注册到 Windows、macOS 或 Linux,并结合单实例处理。这个过程属于发布配置;初学阶段先理解“链接如何告诉应用要打开什么内容”即可。
🧾 小节总结
- 开发环境通常加载 Vite URL,生产环境通常加载本地构建文件。
- 打包后必须检查资源是否被复制到应用包。
- 自定义协议适合统一管理应用内部资源。
- 深链接可以把外部地址转换成应用内页面。
- 本地路径和 URL 参数都需要限制和校验。
❓ 知识问答
Q1:所有 Electron 项目都需要自定义协议吗?
A:不需要。简单项目使用 loadFile 就够了,自定义协议适合有统一资源加载或深链接需求的项目。
Q2:为什么开发环境能打开,打包后却白屏?
A:常见原因是生产路径错误,或者构建资源没有被复制进应用包。
🧪 小练习
在下面的代码中补充生产环境页面路径:
win.loadFile(
// 请在这里编写代码
);
🎉 现在你已经理解了 Electron 资源加载中最容易混淆的开发与生产差异。
