Electron Preload.js和renderer.js上下文隔离问题
eletron 12版本以后默认开启了上下文隔离
webPreferences: {
contextIsolation: true,
}
上下文隔离后, 内存变成了不一样的区域, 通过桥接函数contextBridge.exposeInMainWorld
从preload转移过去的都是复制的内容, 桥接过去的obj也是复制的, 在render中修改并不会影响preload. 甚至ipcRender也不能直接桥接过去, .on
会丢失.
可是renderer中最重要的就是ipc消息交互了. ipcRenderer.on用不了要如何监听ipcMain发过来的消息?
Eletron官方文档中居然都没有写如何桥接.on
,只写了.send
和.invoke
参考这个回答吧: https://stackoverflow.com/questions/59993468/electron-contextbridge
两个人给出了两种方式:都是preload.js
第一种:
const {
contextBridge,
ipcRenderer
} = require("electron");
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
"api", {
send: (channel, data) => {
// whitelist channels
let validChannels = ["toMain"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
}
}
);
第二种:
const { ipcRenderer, contextBridge } = require('electron')
const validChannels = ["toMain", "myRenderChannel"];
contextBridge.exposeInMainWorld(
"api", {
send: (channel, data) => {
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
on: (channel, callback) => {
if (validChannels.includes(channel)) {
// Filtering the event param from ipcRenderer
const newCallback = (_, data) => callback(data);
ipcRenderer.on(channel, newCallback);
}
},
once: (channel, callback) => {
if (validChannels.includes(channel)) {
const newCallback = (_, data) => callback(data);
ipcRenderer.once(channel, newCallback);
}
},
removeListener: (channel, callback) => {
if (validChannels.includes(channel)) {
ipcRenderer.removeListener(channel, callback);
}
},
removeAllListeners: (channel) => {
if (validChannels.includes(channel)) {
ipcRenderer.removeAllListeners(channel)
}
},
}
);
这种方法官方文档已经写了,不推荐,因为会暴露ipc这种高权限api,违背了设置contextBridge的初衷。
要renderer获取preload.js的数据,直接return就可以了,官方就是为了安全才让用复制的数据,
虽然我认为没人会为了安全给自己搞麻烦,除非大厂。