You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron自定义协议scheme无法正常工作问题求助

Electron 29自定义特权协议处理失效及实例无限启动问题解决

问题根源分析

  • 协议处理注册时机错误:同时混用app.on('ready')和app.whenReady(),ready事件触发时whenReady()内的protocol.handle还未执行,导致加载foo://main.html时协议处理逻辑未就绪,Windows系统接管了协议打开请求。
  • 未处理协议激活参数:调用app.setAsDefaultProtocolClient('foo')后,Windows会将协议请求作为命令行参数传递给应用,但未处理这些参数,导致每次触发协议都会启动新的应用实例,最终耗尽系统资源。

修复后的代码示例

import { app, BrowserWindow, protocol } from 'electron';
import path from 'path';

// 提前注册特权协议,必须在app ready前执行
protocol.registerSchemesAsPrivileged([
  {
    scheme: 'foo',
    privileges: {
      bypassCSP: true,
      standard: true,
      secure: true,
      supportFetchAPI: true,
    }
  }
]);

// 防止多实例启动的逻辑
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
  app.quit();
} else {
  app.on('second-instance', (event, commandLine) => {
    // 提取协议请求链接
    const protocolUrl = commandLine.find(arg => arg.startsWith('foo://'));
    if (protocolUrl && win) {
      if (win.isMinimized()) win.restore();
      win.focus();
      // 加载协议对应的内容
      win.loadURL(protocolUrl);
    }
  });

  let win;

  app.whenReady().then(() => {
    // 注册协议处理函数
    protocol.handle('foo', (req) => {
      console.log("处理协议请求:", req.url);
      // 根据请求路径返回对应资源,示例返回本地main.html
      if (req.url === 'foo://main.html') {
        const filePath = path.join(__dirname, 'main.html');
        return protocol.fileProtocol.handle(req, filePath);
      }
      return new Response('Not Found', {
        status: 404,
        headers: { 'content-type': 'text/html' }
      });
    });

    // 创建窗口
    win = new BrowserWindow({
      width: 800,
      height: 600,
      frame: false,
      closable: true,
      webPreferences: {
        preload: path.join(__dirname, 'preload.js'),
        nodeIntegration: false,
        nodeIntegrationInSubFrames: false,
        contextIsolation: true,
      },
    });

    win.loadURL(`foo://main.html`);

    // 仅主实例设置默认协议客户端
    app.setAsDefaultProtocolClient('foo');
  });

  app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit();
  });
}

关键修复点说明

  • 统一使用app.whenReady():放弃app.on('ready'),确保协议处理函数在窗口创建前完成注册,避免加载协议链接时逻辑未就绪。
  • 添加单实例锁:通过app.requestSingleInstanceLock()和second-instance事件处理协议请求,防止重复启动实例,同时激活已有窗口处理新的协议链接。
  • 正确返回协议资源:示例中通过protocol.fileProtocol.handle返回本地HTML文件,可根据需求调整返回逻辑。
  • 延迟设置默认协议客户端:将app.setAsDefaultProtocolClient('foo')放在whenReady()内部,确保仅主实例注册协议关联。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 10:41:19