在现代隔离渲染器进程Electron中使用remote.getGlobal变量



我正在更新几年前使用Electron v1.8.8编写的整个应用程序。据我所知,Electron改变了它的模式,现在主进程和渲染器进程之间默认的预期通信方式是在中间使用一个名为preload.js的模块。
要以旧的方式获取/设置全局变量,首先需要远程模块:

var { remote } = require('electron');

然后像这样获取/设置:

remote.getGlobal('sharedObj').get('user')

我一直试图在preload.js中公开一个api对象,以实现相同的旧功能,但没有成功
如果不设置nodeIntegration: true, contextIsolation: false,我将如何实现这一点?

要在主线程和渲染线程之间发送消息,需要了解进程间通信和上下文隔离。

你是对的,preload.js就像一个中间人。根据我的经验,使用preload.js作为一个脚本,其唯一目的是通过使用定义的通道在主线程和渲染线程之间通信数据,可以实现简单、易读的关注分离。IE:不要在preload.js脚本中放置特定于域的函数。仅添加用于执行特定通信方法的功能。

下面是一个典型的preload.js文件。我已经定义了几个通道来在主线程和渲染线程之间进行通信。PS:您可以使用任何名称/命名约定来命名您的频道。

preload.js(主线程(

const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [
'renderThread:saysHi'
],
// From main to render.
'receive': [
'mainThread:saysHi'
],
// From render to main and back again.
'sendReceive': []
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);

虽然您的main.js文件看起来可能与下面显示的略有不同,但主要关注点是已定义信道renderThread:saysHimainThread:saysHi的接收和传输。

main.js(主线程(

const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;
const nodePath = require("path");
let appWindow;
function createAppWindow() {
const appWindow = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
fullscreen: false,
resizable: true,
movable: true,
minimizable: true,
maximizable: true,
enableLargerThanScreen: true,
closable: true,
focusable: true,
fullscreenable: true,
frame: true,
hasShadow: true,
backgroundColor: '#fff',
show: false,
icon: nodePath.join(__dirname, 'icon.png'),
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
worldSafeExecuteJavaScript: true,
enableRemoteModule: false,
devTools: (! electronApp.isPackaged),
preload: nodePath.join(__dirname, 'preload.js')
}
});
appWindow.loadFile('index.html')
.then(() => {
// Main thread saying hi to the render thread.
appWindow.webContents.send('mainThread:saysHi', 'Hello from the main thread.'); })
.then(() => { 
appWindow.show(); })
return appWindow;
}
// Listen for the render thread saying hi.
electronIpcMain.on('renderThread:saysHi', (event, message) => {
console.log(message); });
}
electronApp.on('ready', () => {
appWindow = createWindow();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});

您的index.html文件将导入您的Javascript文件,该文件将包含在指定频道上侦听和发送消息的代码。

index.html(渲染线程(

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="main-thread-message"></div>
<input type="button" id="render-thread-button" value="Click to say hi to the main thread">
</body>
<script type="module" src="index.js"></script>
</html>

index.js(渲染线程(

let mainThreadMessage = document.getElementById('main-thread-message');
let renderThreadButton = document.getElementById('render-thread-button');
// IIFE - Immediately Invoke Function Expression
(function() {
window.ipcRender.receive('mainThread:saysHi', (message) => {
mainThreadMessage.textContent = message;
});
renderThreadButton.addEventLister('click', () => {
window.ipcRender.send('renderThread:saysHi', 'Hello from the render thread.');
});
})();

在上面的代码中,全局对象window包含ipcRender.sendipcRender.receive,这是preload.js脚本中contextBridge.exposeInMainWorld行下面使用的结构。您可以将ipcRenderreceive/send/invoke重命名为任何您喜欢的名称,但如果您这样做,在使用"html-js"端时也会使用相同的引用。

最新更新