正式情况是这样的,electron中,使用了c做为electron调用程序,而c的使用方法为了全局使用,是在首次加载程序的时候绑定在了window上,例如:
const node_file = require("xx/xx/node_file.node")
window.$node_file = new node_file()
引入方法如上,是在主进程打开窗口后,渲染进程渲染后进行调用。
在现场因为版本原因,从11.0.1 升级到了17.0.1。(此处伏笔) 主窗口打开后一点问题没有。 主窗口大概代码如下:
const electron = require("electron")
const { app, BrowserWindow, ipcMain,crashReporter, protocol, dialog, desktopCapturer } = electron;
const remoteMain = require('@electron/remote/main');
const path = require("path");
function createWindow () {
mainWindow = new BrowserWindow({
show: false,
resizable: true,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
webSecurity: false,
allowDisplayingInsecureContent: true,
allowRunningInsecureContent: true,
webviewTag: true,
enableRemoteModule: true,
preload: xxxx
},
});
}
结果升级后主窗口没问题,但是当某个节点需要打开子窗口的时候,则出了问题。报错如下:
window.$node_file is not a function
依旧老样子,我们先来排查一下原因。
- 排查子窗口创建问题。
const remote = require('@electron/remote');
const { ipcRenderer } = require('electron');
const { BrowserWindow, getCurrentWindow, dialog, shell ,ipcMain } = remote;
const path = require('path');
function createWindow () {
mainWindow = new BrowserWindow({
xx: false,
resizable: true,
webPreferences: {
webSecurity: false,
nodeIntegration: true,
allowDisplayingInsecureContent: true,
allowRunningInsecureContent: true,
webviewTag: true,
enableRemoteModule: true,
preload: xxx
},
});
}
好吧,对比了下,除过引入remote的坐了个小变化之外,其它的其实都没有什么变化。 因为版本升级了 electron在高版本中必须要从 @electron/remote 中获取。 其实倒是也没什么。 此项跳过。
- 引入顺序监测。
因为window的事件绑定是从主进程进行的事件绑定,所以我们监测主进程。发现,主进程全部正常引入,正常调用。 而当我们需要打开子窗口的时候,就出问题了。所以顺序引入是正常的。 这时候我们就发现了新的问题,主进程没问题,而当只有打开子窗口的时候会有问题。 那么问题肯定是出在了子窗口的问题上。
- 子窗口排查
上面其实我贴了代码,大多数是相同的。其实我也没有放在心上。 直到去找人工智能对比了11版本跟17版本的参数区别。 这才发现有个问题,必须要正视一下。 那就是隔离问题。contextIsolation
## 上下文隔离是什么?[](https://www.electronjs.org/zh/docs/latest/tutorial/context-isolation#%E4%B8%8A%E4%B8%8B%E6%96%87%E9%9A%94%E7%A6%BB%E6%98%AF%E4%BB%80%E4%B9%88 "链接到 上下文隔离是什么?")
上下文隔离功能将确保您的 `预加载`脚本 和 Electron的内部逻辑 运行在所加载的 [`webcontent`](https://www.electronjs.org/zh/docs/latest/api/web-contents)网页 之外的另一个独立的上下文环境里。 这对安全性很重要,因为它有助于阻止网站访问 Electron 的内部组件 和 您的预加载脚本可访问的高等级权限的API 。
这意味着,实际上,您的预加载脚本访问的 `window` 对象**并不是**网站所能访问的对象。 例如,如果您在预加载脚本中设置 `window.hello = 'wave'` 并且启用了上下文隔离,当网站尝试访问`window.hello`对象时将返回 undefined。
自 Electron 12 以来,默认情况下已启用上下文隔离,并且它是 _所有应用程序_推荐的安全设置。
重点来了,之前版本是11现在是17 .所以问题是出在了 contextIsolation 上 而contextIsolation 的目标就说:
如果您在预加载脚本中设置
window.hello = 'wave'并且启用了上下文隔离,当网站尝试访问window.hello对象时将返回 undefined。
所以,子窗口创建的时候也必须设置 contextIsolation 为false。这样才可以正确去使用预加载脚本中设置的一些东西,例如方法,监听,属性等等。 当然了,这也是一把双刃剑,具体如何使用,还是得开发者做深入讨论。
好了。BUG解决了。 继续挑战下一个问题吧。