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

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

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

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

示例:

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 文档或 Internet 上的其他地方找到明确的解决方案来将我呈现的 window 设置为参数。

我可能会在 window 准备好后使用 IPC 通信,但它似乎有点太复杂了,直到我只想将变量传递给我的子视图。

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

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

在 "local filepath" 中使用散列或查询听起来有点奇怪,但在我的例子中它是有意义的,因为散列描述了 redux 存储分支在这个 window 中考虑(file://which-code-to-load#which-content).

所以即使我现在对这种方法并不完全放心,我也会选择第二种。

遗憾的是,API 没有提供任何方式在 window 打开时从主进程声明全局变量。我会 post 一个功能请求。

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

// 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

不幸的是,它看起来很复杂。您可能无法将变量添加到 .html 您以一种很好的方式在 electron 中渲染。

当然 - 您可以使用 url,但它会大大降低启动速度(vy 秒),或者您可以在 BrowserWindo 中执行 Javascript,这也会减慢启动速度。

唯一的方法是 IPC 并让 javascript .html 对主进程中的变量不可知。虽然很伤心..

几个方法:

loadURL 查询字符串

。它甚至可能是最简单的。

附加参数

Electron 的文档说 additionalArguments 是:

Useful for passing small bits of data down to renderer process preload scripts.

主要

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) 来获取数组中的最后一项。


IPC 主要/渲染

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

主要

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

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

例如:

处理脚本

在你的主脚本中写:

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

Window 脚本

在 window 脚本中需要它的地方:

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

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

主处理器:

global.id = 1;

渲染处理器:

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

将查询字符串与 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'])

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

处于预加载状态

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 进行同步调用,也许这样更快,但我还没有尝试过。