如何在 Electron 中将参数从主进程传递到渲染进程

How to pass parameters from main process to render processes in Electron

本文关键字:进程 Electron 参数      更新时间:2023-09-26

我有一个可以打开不同窗口的Electron应用程序。

在应用程序启动时,应用程序打开一组窗口(加载相同的HTML和JS文件),但带有参数来更改每个窗口显示的信息。

例:

app.on('ready', async () => {
  ...
  // open window for stuff 1
  win1 = new BrowserWindow({
     width: 1024,
     height: 728
  });
  win1.loadURL(`file://${__dirname}/app/app.html?id=1`);
  // open window for stuff 2
  win2 = new BrowserWindow({
     width: 1024,
     height: 728
  });
  win2.loadURL(`file://${__dirname}/app/app.html?id=2`);

显然,在路径中传递参数 file://不起作用。我在 Electron 文档或互联网上的其他地方找不到明确的解决方案来将渲染的窗口调整为参数。

我可能可以在窗口准备就绪后使用 IPC 通信,但在我只想将变量传递给我的子视图之前,这似乎有点太复杂了。

PS:老实说,我的应用程序是用 React/Redux 构建的,我想传递给视图的参数是监听此视图的 redux 存储密钥。

几种方法:

加载网址查询字符串

其他人发布的查询字符串方法似乎工作正常。它甚至可能是最简单的。

附加参数

Electron的文档说additionalArguments是:

用于将少量数据向下传递到渲染器进程预加载 脚本。

主要

const win = new BrowserWindow({
  width: 800,
  height: 600,
  backgroundColor: '#000000'
  webPreferences: {
    additionalArguments: ["myvarvalue", "secondvarvalue", "--another=something"]
  }
});

渲染

window.process.argv将看起来像这样:

["--num-raster-threads=2",
"--enable-gpu-memory-buffer-compositor-resources",
"--enable-gpu-async-worker-context",
...
"--renderer-client-id=4",
"myvarvalue",
"secondvarvalue",
"--another=something"]

它将附加一个字符串数组。您可以执行一些window.process.argv.slice(-3)操作来获取数组中的最后一项。


工控机主/渲染

就像你说的,对于你想要做的事情来说似乎很复杂,但也许这会有所帮助:

主要

const { ipcMain } = require('electron');
var mainProcessVars = {
  somevar: "name",
  anothervar: 33
}
ipcMain.on('variable-request', function (event, arg) {
  event.sender.send('variable-reply', [mainProcessVars[arg[0]], mainProcessVars[arg[1]]]);
});

渲染

const { ipcRenderer } = electron;
electron.ipcRenderer.send('variable-request', ['somevar', 'anothervar']);
ipcRenderer.on('variable-reply', function (event, args) {
  console.log(args[0]); // "name"
  console.log(args[1]); // 33
});

这种方式允许您发送字符串以外的数据。

根据原子源代码,查询字符串方法是一种非常简单的可靠方法,特别是当我们只需要传递一个唯一的字符串参数时:

// main process
win1.loadURL(`file://${__dirname}/app/app.html?id=${id}`);
// rendered process
console.log(global.location.search);

https://github.com/electron/electron/issues/6504

使用查询字符串和win.loadFile()

// main process or renderer process 1
data = {"age": 12, "healthy": true}
let win = new BrowserWindow({
        webPreferences: {
          nodeIntegration: true
        }
      });
win.loadFile("public/print.html", {query: {"data": JSON.stringify(data)}});
// renderer process 2
const querystring = require('querystring');
let query = querystring.parse(global.location.search);
let data = JSON.parse(query['?data'])

我们可以注入 Javascript 代码执行(在窗口 did-finish-load 事件上)并使用正确的 redux 状态部分触发反应重新渲染。但它需要在渲染过程中执行额外的生命周期步骤。

在"本地文件路径"中使用哈希或查询听起来有点奇怪,但就我而言,这是有意义的,因为哈希描述了在此窗口中要考虑的 redux 存储分支(file://which-code-to-load#which-content)。

因此,即使我现在对这种方法并不完全满意,我也会选择第二种选择。

遗憾的是,API 没有提供任何在窗口打开时从主进程声明全局变量的方法。我将发布功能请求。

实际上使用调用和句柄组合也可以工作。在我的示例中,我特别需要在一开始就建立连接。

预加载中

const { ipcRenderer } = require('electron')
window.addEventListener('DOMContentLoaded', () => {
  ipcRenderer.invoke('init').then(res => {
    window.alert(res)
    // render(e(App, {}), elem)
  })
})

而在主要

const { ipcMain } = require('electron')
ipcMain.handle('init', async () => {
  return 'Abc'
})

您甚至可以尝试通过ipcRenderer.sendSync进行同步调用,也许这更快,但我还没有尝试过。

例如:

流程脚本

在主脚本中写入:

global.varsForWindow = {
    platform: process.platform
};

窗口脚本

在窗口脚本中需要它的位置:

var varsFromMainScript = require('electron').remote.getGlobal('varsForWindow');
console.log(varsFromMainScript.platform);

您可以使用global变量在主处理器和渲染器处理器之间共享数据:

主处理器:

global.id = 1;

渲染器处理器:

let id = remote.getGlobal('id');

不幸的是,这似乎很复杂。您可能无法以良好的方式在电子中渲染.html添加变量。

当然 - 你可以使用 url,但它会非常减慢启动速度(vy seconds),或者你可以在 BrowserWindo 中执行 Javascript,这也会减慢启动速度。

唯一的方法是IPC和让javascript.html与主进程中的变量无关。虽然很伤心..