【Electron】IpcMainEvent 参数使用总结

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]);
    });

实践代码示例:

后面也有找到一个使用MeesageChannelMain的另一个示例:
https://gist.github.com/johannesgiani/a27fab2121dadb1b37820e891dac0aaf

复制代码
# 传输的MessagePorts
    
    ## 主进程
        
        // 先前一直使用once,导致渲染进程的热更新,就会丢失通信,所以改为on,
        mainWindow.webContents.on('did-finish-load', () => {
            const { port1, port2 } = new MessageChannelMain();
            
            port2.postMessage({ test: 123 })
            port2.on('message', (event) => {
                console.log('main port2 on message', event.data);
                
                // 收到渲染进程消息后,再回一条
                port2.postMessage({ from: 'main', echo: event.data });
            });
            port2.start();
            console.log('[main] posting port1 to renderer');
            
            // 让主进程稍微延迟发送 port,用于测试功能
            setTimeout(() => {
              mainWindow.webContents.postMessage('main-message', { hello: 'world' }, [port1]);
            }, 500); // 等 React mount
        });
        
    ## preload.js配置
        可以配置在preload.js中的contextBridge.exposeInMainWorld的顶部,但绝对不能在contextBridge.exposeInMainWorld内部配置,这个和渲染进程的contextBridge不冲突,但需要各自配置各自的

        const windowLoaded = new Promise(resolve => {
          window.onload = resolve
        })
        
        // 监听来自主进程的 webContents.postMessage
        ipcRenderer.on('main-message', async (event: any) => {
          console.log('[preload] got main-message, forwarding port to window.main world', event.data, 'ports:', event.ports);
          await windowLoaded;
        
          // 把 port 转发给页面主世界
          // 注意 event.ports 是一个可传递的 MessagePortMain 实例数组
          window.postMessage('main-message', '*', event.ports);
        });
    
    ## 渲染进程
        // 设置 window.onmessage 接受来自 preload 转发的 port
        window.onmessage = (event) => {
          console.log('[renderer] actual event.data =', event.data);
    
          // 只处理预期的 channel 名称
          if (event.source !== window || event.data !== 'main-message') {
            // 可能是别的来源(iframe、devtools 等),忽略
            return;
          }
    
          console.log('[renderer] received postMessage from preload, data=', event.data, 'ports=', event.ports);
    
          const port = event.ports && event.ports[0];
          if (!port) {
            console.log('[renderer] No port received!');
            return;
          }
    
          // 给 port 注册 onmessage
          port.onmessage = (e) => {
            console.log('[renderer] port.onmessage:', e.data);
          };
    
          // 向主进程发一条消息(通过 port)
          port.postMessage({ from: 'renderer', note: 'hello main! (via port)', ts: Date.now() });
    
          // 测试:再发送一个响应来模拟业务
          setTimeout(() => {
            port.postMessage({ from: 'renderer', note: 'delayed message', ts: Date.now() });
          }, 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
相关推荐
月弦笙音1 小时前
【包管理器】pnpm、npm、cnpm、yarn 深度对比
前端
吹水一流1 小时前
微信小程序页面栈:从一个 Bug 讲到彻底搞懂
前端·微信小程序
j***82701 小时前
【MyBatisPlus】MyBatisPlus介绍与使用
android·前端·后端
Python大数据分析@1 小时前
我把pdfplumber整成了可以拖拉拽的web软件
前端·pdf
小华同学ai1 小时前
终于有人帮你整理好了,火爆的“系统级提示词”支持ChatGPT、Claude、Gemini、xAI的
前端·后端·github
葡萄城技术团队1 小时前
SpreadJS 电子表格权限管控设置指南
前端
HashTang1 小时前
一个人就是一支队伍:从 Next.js 到显示器,聊聊我的“全栈续航”方案
前端·后端·程序员
朕的剑还未配妥1 小时前
vue2中transition使用方法解析,包含底部弹窗示例、样式未生效踩坑记录
前端·vue.js
q***48411 小时前
Redis Desktop Manager(Redis可视化工具)安装及使用详细教程
android·前端·后端