Electron上下文隔离进程间的四种通信方式示例详解

文章详细介绍了Electron中主进程和渲染进程间的四种通信方式,包括渲染器到主进程的单向通信、双向通信,主进程到渲染器的双向通信以及渲染器间的消息传递。强调了上下文隔离的通信方式在使用Vue等前端框架时的优势。
摘要由CSDN通过智能技术生成

一、Electron 进程之间的通信

Electron进程通信大致可分为主进程和渲染进程两种:

  • 主进程:指的就是 node.js 进程,node.js 只有一个进程。
  • 渲染进程:可以简单理解为一个 Chromium 的 web 页面,可以有多个渲染进程。

ipc通信就是在主进程和渲染进程之间通信
​​​推荐使用上下文隔离渲染器进程进行通信。这种方式的好处是无需在渲染进程中直接使用 ​​ipcRenderer ​​​发送消息,当我们使用​​ vue​​​ 或者其他前端框架开发界面时,上下文隔离方式使用起来更加方便,基本上感受不到 ​​electron ​​对前端框架的影响。

二、上下文隔离的进程间通信方式有四种,示例如下

示例背景如下
在vue项目中创建一个electron文件夹

  • main.js(主进程文件)
  • preload.js(预加载脚本)

1、 渲染器到主进程(单向)

ipcMain.on 和 ipcRenderer.send
示例描述:从 渲染进程中操作主进程的关闭操作,也就是从渲染进程中关闭electron

(1)主进程:electron/main.js

const { ipcMain } = require('electron');
ipcMain.on('operation-window',function(event,operationType){
    switch(operationType){
        case "max"://窗口 最大化
            win.maximize()
            break;
        case 'restoreDown'://窗口 向下还原
             win.unmaximize()
            break;
        case "min"://窗口 最小化
             win.minimize()
            break;
        case 'close'://窗口 关闭
             win.close()
        break;
    }
})

(2)预加载文件:electron/preload.js

//向渲染器进程暴露一个全局的 window.electronAPI 变量。
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
    operationWindow: (operationType) => ipcRenderer.send('operation-window', operationType),
})

(3)渲染进程文件:xxx.vue

<div>
    <button @click="onClickClose">关闭窗口</button>
</div>

<script lang="ts" setup>
    const onClickClose = () => {
        if(window.electronAPI && window.electronAPI.operationWindow){
            window.electronAPI.operationWindow('close')                            
        }
    }
</script>

2、渲染器进程到主进程(双向)

ipcMain.handle 和 ipcRenderer.invoke
示例描述:从渲染进程中 调用 主进程的弹窗选择文件后返回文件路径给 渲染进程

  • 在主进程中,我们将创建一个 ​​handleFileOpen()​​​ 函数,它调用electron的 ​​dialog.showOpenDialog​​​ 并返回用户选择的文件路径值。
  • 每当渲染器进程通过 ​​dialog:openFile​​​ 通道发送 ​​ipcRender.invoke​​​ 消息时,此函数被用作一个回调。然后,返回值将作为一个 Promise 返回到最初的 ​​invoke​​ 调用。

(1)主进程:electron/main.js

const { ipcMain,dialog } = require('electron');
async function handleFileOpen() {
  const { canceled, filePaths } = await dialog.showOpenDialog()//调用electron的打开文件弹窗
  if (canceled) {
    return
  } else {
    return filePaths[0] // 返回文件名给渲染进程
  }
}
ipcMain.handle('dialog:openFile',handleFileOpen)

(2)预加载文件:electron/preload.js

import { contextBridge, ipcRenderer } from 'electron'

contextBridge.exposeInMainWorld('electronAPI', {
  openFile: () => ipcRenderer.invoke('dialog:openFile')
})

(3)渲染进程文件:xxx.vue

<div>
    <button @click="onSelectFile">选择文件</button>
</div>

<script lang="ts" setup>
    const onSelectFile = async () => {
        if(window.electronAPI && window.electronAPI.openFile){
            const filePath = await window.electronAPI.openFile()  
            console.log("选择的文件路径是:" + filePath)                          
        }
    }
</script>

3、主进程到渲染器进程(双向)

win.webContents.send 和 ipcRenderer.on
event.sender.send 和 ipcMain.on
示例描述:从主进程的托盘上下文菜单每次被点击都通知 渲染进程, 渲染进程接收后,告诉主进程收到了。

  • 将消息从主进程发送到渲染器进程时,需要指定是哪一个渲染器接收消息。
  • 消息需要通过其 ​​WebContents​​​ 实例发送到渲染器进程。此 WebContents 实例包含一个 ​​send​​​ 方法,其使用方式与 ​​ipcRenderer.send​​ 相同。

(1) 主进程通知渲染进程【win.webContents.send 和 ipcRenderer.on】

① 主进程:electron/main.js
const { ipcMain, Tray, Menu } = require('electron');
//系统托盘
    let appTray = new Tray(iconPath)
    const trayContextMenu = Menu.buildFromTemplate([
    {
        label: "打开安信",
        click:() => {
            win.webContents.send('update-counter',1)//每次点击都告诉渲染进程,我被点击了一次
        }
    },
    ])
//系统托盘的提示文本
appTray.setToolTip('安信');
//点击系统托盘打开窗口
appTray.on('click',() => {
    win.show();
});
//系统托盘右键点击事件
appTray.on('right-click',() => {
    appTray.popUpContextMenu(trayContextMenu);//显示系统菜单
});
② 预加载文件:electron/preload.js
//向渲染器进程暴露一个全局的 window.electronAPI 变量。
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
    onUpdateCounter: (callback) => ipcRenderer.on('update-counter', callback);
})
③ 渲染进程文件:xxx.vue
<script lang="ts" setup>
    let total = 0;
    window.electronAPI.onUpdateCounter((event, value) => {
        console.log("event---",event)
        console.log("value---",value)
        total += value
    })
</script>

(2)如果渲染进程收到消息后想要回复主进程【event.sender.send 和 ipcMain.on】

① 渲染进程文件:xxx.vue
//在渲染器进程中,使用 ​​event​​​ 参数,通过 ​​counter-value​​ 通道将回复发送回主进程。
<script lang="ts" setup>
    let total = 0;
    window.electronAPI.onUpdateCounter((event, value) => {
        console.log("event---",event)
        console.log("value---",value)
        total += value
        event.sender.send('counter-value', '累计点击次数是:',total) // 发送消息到主进程
    })
</script>
② 主进程:electron/main.js
//在主进程中,监听 ​​counter-value​​ 事件并适当地处理它们。
const { ipcMain} = require('electron');
ipcMain.on('counter-value',function(event,value){
    console.log("接收渲染进程发过来的消息===",value)
})

4、渲染器进程到渲染器进程

没有直接的方法可以使用 ​​ipcMain​​​ 和 ​​ipcRenderer​​ 模块在 Electron 中的渲染器进程之间发送消息。为此,我们有两种选择:
(1) 将主进程作为渲染器之间的消息代理。这需要将消息从一个渲染器发送到主进程,然后主进程将消息转发到另一个渲染器。

主进程 代码

/**
 * 接收渲染进程 转发消息 的通知  
 * @param {Object} event
 * @param {String} windowName 目标窗口名称
 * @param {Array} params 发送参数
 */
ipcMain.on('post-message',function(event,windowName,params) {
	if(windows[windowName]){
		windows[windowName].webContents.send('get-message',params);//转发给指定窗口
	}
})

预加载文件 代码

//向渲染器进程暴露一个全局的 window.electronAPI 变量。
const { contextBridge, ipcRenderer, app } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
	postMessage: (windowName,params) => ipcRenderer.send('post-message',windowName,params),//跨窗口发送消息,接收渲染进程的转发消息的通知
	getMessage: (callback) => ipcRenderer.on('get-message', callback),//把消息通知到指定窗口
})

渲染进程1 代码 (发送)

if(window.electronAPI && window.electronAPI.postMessage){
	window.electronAPI.postMessage('childWindow',{test:"发送给子窗口的数据~~"});
}

渲染进程2 代码 (接收)

if(window.electronAPI && window.electronAPI.getMessage){
		window.electronAPI.getMessage((event,params) => {
			console.log(params)//打印结果:{test:"发送给子窗口的数据~~"}
		})
	}

(2) 从主进程将一个 MessagePort 传递到两个渲染器。这将允许在初始设置后渲染器之间直接进行通信。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值