IPCMain 介绍:
IPCMain 从主进程到渲染进程的异步通信,要想与渲染进程通信,则需通过preload配置通信桥。
IpcRenderer 从渲染进程到主进程的异步通信。

通信桥:

contextBridge.exposeInMainWorld(
    'electron': {
        ipcRenderer: {
            ...ipcMain.API        
        }    
    }
)

IpcMainEvent 参数总结:

  • type 字符串
  • 可能的值包括frame
事件类型
	 // 示例值
	    event.type = "frame";
	    // 可能的其他值:根据实际应用可能还有 "window", "dialog" 等

processId Integer

  • 发送该消息的渲染进程内部的ID
**渲染进程 ID**
    // 示例值
    event.processId = 12345;
    // 这标识了发送消息的渲染进程的唯一ID

frameId Integer

  • 发送该消息的渲染进程框架的ID(可能是iframe)
	渲染进程框架 ID
    
	    // 示例值
	    event.frameId = 1; // 主框架
	    // 或
	    event.frameId = 2; // iframe框架
	

returnValue any
- 如果对此赋值,则该值会在同步消息中返回

同步消息返回值
    
    // 示例:在同步IPC消息中设置返回值
    event.returnValue = "操作成功";
    // 或
    event.returnValue = { data: "返回的数据", status: "success" };
    
    示例:
        主进程:
            ipcMain.on('channel-name', (event, data) => {
                event.returnValue = '消息'        
            })
        
        渲染进程:必须要用sendSync才能获取到内容
            const getValue = ipcRenderer.sendSync('channel-name')
            console.log(getValue) // 消息

sender WebContents

  • 返回webContents 发送消息的内容
发送消息的WebContents
    
    sender.webContents = BrowserWindow.webContents
    
    示例(异步):
        // 主进程
            ipcMain.on('channel-name', (event: Electron.IpcMainEvent, data) => {
              console.log('收到消息:', data)
              
              event.sender.send('response-channel', {
                status: 'success',
                message: '处理完成',
                result: data * 2
              })
            })
            
        // 渲染进程
        
          ipcRenderer.send(
            'channel-name',
            50
          )
      
          ipcRenderer.on('response-channel', (getValue: any) => {
              
            console.log(getValue)
             结果:{
                  "status": "success",
                  "message": "处理完成",
                  "result": 100
              }
          })

senderFrame WebFrameMain | null只读

  • 发送此消息的帧。null 如果在帧已导航或已销毁后访问此消息,则可能为空。
发送消息的框架
    
    // 示例:检查发送框架
        if (event.senderFrame) {
          console.log(event.senderFrame.url); // 框架的URL
        } else {
          console.log("框架已销毁或不存在");
        }

ports MessagePortMain []

  • 此消息传输的消息端口列表

使用场景:
MessagePort 是需要“专线高速公路”时才会用的。普通路(IPC)不够用时再用它
官方推荐使用MessagePort的典型场景:

  • 高吞吐消息
  • 长连接
  • 设备驱动
  • 日志流
  • WebRTC媒体包通信
  • 持续大量事件流
    若是高频业务(如:蓝牙流、TCP流、日志)必须要独立一个MessageChannelMain()
// 主进程
    const chBLE = new MessageChannelMain();
    
    const chTCP = new MessageChannelMain();
    
    const chLog = new MessageChannelMain();
    
// preload
    ipcRenderer.on('port-ble', (e) => window.postMessage('port-ble', '*', e.ports));
    ipcRenderer.on('port-tcp', (e) => window.postMessage('port-tcp', '*', e.ports));
    ipcRenderer.on('port-log', (e) => window.postMessage('port-log', '*', e.ports));
    
// channel
    window.addEventListener("message", (e) => {
      if (e.data === "port-ble") setupBLE(e.ports[0]);
      if (e.data === "port-tcp") setupTCP(e.ports[0]);
    });

实践代码示例:
参考:https://gist.github.com/johannesgiani/a27fab2121dadb1b37820e891dac0aaf

# main 方法

    import chalk from 'chalk';
    import { MessageChannelMain } from 'electron';
    
    class ChannelMessageManager {
      webContents: Electron.WebContents;
      channel: MessageChannelMain;
      portToRenderer: Electron.MessagePortMain;
      port: Electron.MessagePortMain | null;
    
      constructor(mainWindow: Electron.WebContents) {
        this.webContents = mainWindow;
        this.port = null;
        // 标注:最初采用了did-finish-load , 或者ipcMain.on,在preload通信桥中写全局调用,然后想在渲染进程直接调用window.on('message', (event) => console.log(event));但都会在渲染进程更新时容易丢掉通信通道,所以采用目前这套方案是目前最稳妥的
       ipcMain.on('main-to-render-message', (event) => {
          // 创建消息通道
          const { port1, port2 } = new MessageChannelMain();
          this.port = port1;
          
          this.messageChannel()
    
          event.sender.postMessage(
            'send-message',
            { type: 'main-ready' },
            [port2]
          )    
        }
      }
      
      messageChannel() {
       // render to main message
        this.port1.on('message', (event) => {
          console.log(chalk.bgGreenBright('[main] got from renderer:'), event.data);
          // mian send message to render
          this.port1.postMessage({ from: 'main', echo: 'initialized' });
        });
      }
    }
    
    export default ChannelMessageManager;


# preload js

    /** 设置消息通道 */
    setupMessageChannel(callback?: (...args: unknown[]) => void) {
      ipcRenderer.send('main-to-render-message')
      const subscription = (event: IpcRendererEvent) => {
        const port = event.ports[0];
        port.onmessage = (messageEvent) => {
          callback && callback(messageEvent.data)
        }
    
        (window as any).messagePort = port
      }
      ipcRenderer.on('message', subscription);
      return () => {
        ipcRenderer.removeListener('message', subscription);
      }
    },
    /** 通过消息通道发送消息 */
    postMessageToPort(message: any) {
      (window as any)?.messagePort.postMessage(message);
    }
    
    
# 渲染进程

    ipcRenderer.setupMessageChannel((data) => {
      console.log('收到渲染进程消息:', data)
    })
    
    setTimeout(() => {
      // 发送数据
      ipcRenderer.postMessageToPort({
        type: 'scan-start',
        data: 5000
      })
    }, 500);

reply Function
将 IPC 消息发送到渲染器框架的函数,该渲染器框架发送当前正在处理的原始消息。 您应该使用“reply”方法回复发送的消息,以确保回复将转到正确的进程和框架。
channel 细绳
…args 任何[]

#异步消息处理
    
    ## 主进程
        ipcMain.on('channel-name', (event, data) => {
          console.log('收到消息:', data)
          
          // 使用 reply 方法回复
          event.reply('response-channel', {
            status: 'success',
            message: '处理完成',
            result: data * 2
          })
        })
        
    ## 渲染进程
        // 异步消息
        ipcRenderer.send('channel-name', 5)
        ipcRenderer.on('response-channel', (response) => { // 注意参数,我这里的preload配置没有传送回来event
          console.log('收到回复:', response) // {status: 'success', message: '处理完成', result: 10}
        })
    
#同步消息处理
    
    ## 主进程
        
        ipcMain.on('sync-calculation', (event, data) => {
          console.log('同步计算请求:', data)
          
          // 对于同步消息,设置 returnValue
          if (data.operation === 'add') {
            event.returnValue = data.a + data.b
          } else if (data.operation === 'multiply') {
            event.returnValue = data.a * data.b
          } else {
            event.returnValue = null
          }
        })
        
    ## 渲染进程
    
        // 同步消息
        const result = ipcRenderer.sendSync('sync-calculation', {
          operation: 'add',
          a: 10,
          b: 20
        })
        console.log('同步结果:', result) // 30
Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐