开发公司Electron 进程间通信的四种方式

在electron开发公司中进行使用 ipcMain 和 ipcRenderer 模块,开发公司通过开发人员定义的“通道”开发公司传递消息来进行通信。
开发公司新的版本中electron开发公司推荐使用上下文隔离渲开发公司染器进程进行通信,开发公司这种方式的好处是无需开发公司在渲染进程中直接使用ipcRenderer发送消息,开发公司这种在渲染进程中调用nodejs开发公司对象的方法对于渲染进开发公司程有侵入性。开发公司当我们使用vue开发公司或者其他前端框架开发界面时,开发公司上下文隔离方式使用起开发公司来更加方便,开发公司基本上感受不到electron开发公司对前端框架的影响。

上下文隔离的方式有四种:

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

要将单向 消息从渲染器进程发送到主进程,您可以使用 ipcRenderer.send API 发送消息,然后使用 ipcMain.on API 接收。通常使用场景是从 Web 向主进程发送消息。

使用 ipcMain.on 监听事件

在主进程中,使用 ipcMain.on 在 set-title 通道上设置一个 IPC :

const handleSetTitle = (event, title) => {  const webContents = event.sender  const win = BrowserWindow.fromWebContents(webContents)  win.setTitle(title)}ipcMain.on('set-title', handleSetTitle)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

上面的 handleSetTitle 回调函数有两个参数:一个 IpcMainEvent 结构和一个 title 字符串。 每当消息通过 set-title 通道传入时,此函数找到附加到消息发送方的 BrowserWindow 实例,并在该实例上调用win.setTitle函数设置窗口标题。

通过预加载脚本暴露 ipcRenderer.send

要将消息发送到上面创建的监听器,您可以使用 ipcRenderer.send。默认情况下,渲染器进程没有权限访问 Node.js 和 Electron 模块。 作为应用开发者,你需要使用 contextBridge 来选择要从预加载脚本中暴露哪些 API。

在您的预加载脚本中添加以下代码,向渲染器进程暴露一个全局的 window.electronAPI 变量。

import { contextBridge, ipcRenderer } from 'electron'contextBridge.exposeInMainWorld('electronAPI', {    setTitle: (title) => ipcRenderer.send('set-title', title)})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后我们就能够在渲染器进程中使用
window.electronAPI.setTitle() 函数。

构建渲染器进程 UI

在 BrowserWindow 加载的我们的 HTML 文件中,添加一个由文本输入框和按钮组成的基本用户界面:

<!DOCTYPE html><html>  <head>    <meta charset="UTF-8">    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">    <title>Hello World!</title>  </head>  <body>    Title: <input id="title"/>    <button id="btn" type="button">Set</button>    <script src="./renderer.js"></script>  </body></html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

为了使这些元素具有交互性,我们将在导入的 renderer.js 文件中添加几行代码,以利用从预加载脚本中暴露的 window.electronAPI 功能:

const setButton = document.getElementById('btn')const titleInput = document.getElementById('title')setButton.addEventListener('click', () => {    const title = titleInput.value    window.electronAPI.setTitle(title)});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这种方式只能把消息从web中发送到主进程,并不能从主进程中获取到返回值。

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

双向 IPC 的一个常见应用是从渲染器进程代码调用主进程模块并等待结果。 这可以通过将 ipcRenderer.invoke 与 ipcMain.handle 搭配使用来完成。

我们依然通过一个示例来了解这种通信方式:

使用 ipcMain.handle 监听事件

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

async function handleFileOpen() {  const { canceled, filePaths } = await dialog.showOpenDialog()  if (canceled) {    return  } else {    return filePaths[0] // 返回文件名给渲染进程  }}ipcMain.handle('dialog:openFile', handleFileOpen)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

通过预加载脚本暴露 ipcRenderer.invoke

在预加载脚本中,我们暴露了一个单行的 openFile 函数,它调用并返回 ipcRenderer.invoke(‘dialog:openFile’) 的值。

import { contextBridge, ipcRenderer } from 'electron'contextBridge.exposeInMainWorld('electronAPI', {  openFile: () => ipcRenderer.invoke('dialog:openFile')})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

构建渲染器进程 UI

在渲染器中调用
window.electronAPI.openFile调用打开文件对话框,并获取打开的文件名,并显示在界面上。

<!DOCTYPE html><html>  <head>    <meta charset="UTF-8">    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">    <title>Dialog</title>  </head>  <body>    <button type="button" id="btn">Open a File</button>    File path: <strong id="filePath"></strong>    <script src='./renderer.js'></script>  </body></html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

渲染器进程脚本

const btn = document.getElementById('btn')const filePathElement = document.getElementById('filePath')btn.addEventListener('click', async () => {  const filePath = await window.electronAPI.openFile()  filePathElement.innerText = filePath})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

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

使用 webContents 模块发送消息

在菜单中通过使用 webContents.send 将 IPC 消息从主进程发送到目标渲染器。

const menu = Menu.buildFromTemplate([    {      label: app.name,      submenu: [        {          click: () => mainWindow.webContents.send('update-counter', 1),          label: 'Increment',        },        {          click: () => mainWindow.webContents.send('update-counter', -1),          label: 'Decrement',        }      ]    }  ])  Menu.setApplicationMenu(menu)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

通过预加载脚本暴露 ipcRenderer.on

使用预加载脚本中的 contextBridge 和 ipcRenderer 模块向渲染器进程发送消息:

import { contextBridge, ipcRenderer } from 'electron'contextBridge.exposeInMainWorld('electronAPI', {    onUpdateCounter: (callback) => ipcRenderer.on('update-counter', callback)})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

加载预加载脚本后,渲染器进程应有权访问
window.electronAPI.onUpdateCounter() 监听器函数。

构建渲染器进程 UI

<!DOCTYPE html><html>  <head>    <meta charset="UTF-8">    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">    <title>Menu Counter</title>  </head>  <body>    Current value: <strong id="counter">0</strong>    <script src="./renderer.js"></script>  </body></html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

更新 HTML 文档中的值

const counter = document.getElementById('counter')window.electronAPI.onUpdateCounter((_event, value) => {    const oldValue = Number(counter.innerText)    const newValue = oldValue + value    counter.innerText = newValue})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

返回一个回复

对于从主进程到渲染器进程的 IPC,没有与 ipcRenderer.invoke 等效的 API。 不过,您可以从 ipcRenderer.on 回调中将回复发送回主进程。

在渲染器进程中,使用 event 参数,通过 counter-value 通道将回复发送回主进程。

const counter = document.getElementById('counter')window.electronAPI.onUpdateCounter((event, value) => {  const oldValue = Number(counter.innerText)  const newValue = oldValue + value  counter.innerText = newValue  event.sender.send('counter-value', newValue) // 发送消息到主进程})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在主进程中,监听 counter-value 事件并适当地处理它们。

//...ipcMain.on('counter-value', (_event, value) => {  console.log(value) // 将打印到 Node 控制台})//...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4. 渲染器进程到渲染器进程

没有直接的方法可以使用 ipcMain 和 ipcRenderer 模块在 Electron 中的渲染器进程之间发送消息。 为此,我们有两种选择:

  • 将主进程作为渲染器之间的消息代理。 这需要将消息从一个渲染器发送到主进程,然后主进程将消息转发到另一个渲染器。
  • 从主进程将一个 MessagePort 传递到两个渲染器。 这将允许在初始设置后渲染器之间直接进行通信。

Electron与Vue进程通信

上面我们介绍了Electron的四种进程间通信方式,那么将Electron和Vue结合起来,其本质依然是主进程与渲染进程之间的通信,通信方式不会由什么变化,只是目前比较流行的TS编程方式会让一些人束手无策,会报一些属性不存在的错误,这就需要我们去为TS声明这些额外的属性。例如:

  1. 注册上下文隔离接口

在预加载脚本中添加如下代码:

import os from 'os';import { contextBridge } from 'electron';contextBridge.exposeInMainWorld('electronAPI', {  platform: os.platform(),});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.为TS声明类型

// src/types/global.d.tsexport interface IElectronAPI {  platform: string;}declare global {  interface Window {    electronAPI: IElectronAPI;  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.在Vue中调用接口

// src/App.vue<script setup lang="ts">// This starter template is using Vue 3 <script setup> SFCs// Check out https://vuejs.org/api/sfc-script-setup.html#script-setupimport HelloWorld from './components/HelloWorld.vue';const platform = window.electronAPI.platform;</script><template>  <img alt="Vue logo" src="./assets/logo.png" />  <HelloWorld :msg="`Hello Vue 3 + TypeScript + Vite in ${platform}`" /></template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发