Electron.js:如何为 window 创建单独的下载 webContents.session?

Electron.js: how to create a separate download webContents.session for a window?

我有一个 Electron file manager app,它为不同的目的创建了 2 windows:

每个都有自己的 will-download 听众附加到他们的会话。但由于某种原因,quickView 监听器覆盖了 main 监听器。

Window 1

在下一行中,我正在为“主”进程创建一个 will-download 侦听器。此侦听器的目的是下载文件:

https://github.com/aleksey-hoffman/sigma-file-manager/blob/55fd2462cf83898610883191807b7488fb5bdf89/src/utils/downloadManager.js#L133

win.webContents.session.on('will-download', listener)

下一行中的windows.main参数是上一行中的win引用:

https://github.com/aleksey-hoffman/sigma-file-manager/blob/55fd2462cf83898610883191807b7488fb5bdf89/src/electronMain.js#L516

const resultInfo = await downloadManager.download(windows.main, {

Window 2

在下一行中,我正在为“quickView”window 创建一个 will-download 侦听器。此侦听器的目的是检测不支持的文件(在 Chromium 中触发下载事件)并阻止下载事件:

https://github.com/aleksey-hoffman/sigma-file-manager/blob/55fd2462cf83898610883191807b7488fb5bdf89/src/electronMain.js#L232

windows.quickViewWindow.webContents.session.once('will-download', _willDownloadHandler)

我还没有找到另一种方法来检测不受支持的文件,这就是我首先使用 will-download 事件的原因。

问题

出于某种原因,quickView window 的 will-download 处理程序覆盖了 main 的处理程序:

当我在这里触发应用更新下载事件时(来自main进程):

https://github.com/aleksey-hoffman/sigma-file-manager/blob/55fd2462cf83898610883191807b7488fb5bdf89/src/electronMain.js#L516

const resultInfo = await downloadManager.download(windows.main, {

它触发 quickView 渲染器的事件处理程序 window:

https://github.com/aleksey-hoffman/sigma-file-manager/blob/55fd2462cf83898610883191807b7488fb5bdf89/src/electronMain.js#L241

function _willDownloadHandler (event, item, webContents) {
  ...
  windows.main.webContents.send('load:webview::failed', {path: fileURL})

部分修复

我通过为 quickView window 的会话指定自定义分区名称,部分解决了 this commit 中的问题,因此它不使用默认会话,也不覆盖由 main:

创建的 will-download 侦听器

主要流程:

windows.quickViewWindow = new electron.BrowserWindow({
  ...
  webPreferences: {
    partition: 'quickPreview',

...

windows.quickViewWindow.webContents.session.once(
  'will-download',
  (event, item, webContents) => {
    event.preventDefault()
    ...
  }
)

quickViewWindow.html:

ipcRenderer.on('load:webview', (event, data) => {
  ...
  webviewNode.setAttribute('partition', 'quickPreview')

但是这个修复导致了另一个问题:

我认为这可能是由 electron-builder-plugin 创建的自定义 app:// 协议引起的。弹出窗口似乎是由“应用程序”触发的 link.

或者可能是因为我在这条线附近的某处创建 window 时错误地设置了协议:

https://github.com/aleksey-hoffman/sigma-file-manager/blob/47ce65bdac78e5c9b17315f16623d40d81dcf1bb/src/electronMain.js#L203

重现:

  1. 下载项目
git clone https://github.com/aleksey-hoffman/sigma-file-manager.git
cd sigma-file-manager
npm install
git checkout 47ce65b
npm run electron:build
  1. 安装来自 ./dist_electron
  2. 的内置应用
  3. 在应用程序启动期间,您可以看到弹出窗口

备注:

我刚刚回滚了 47ce65b 提交并添加了一些测试值 所以更容易调试

要切换到最新提交并创建生产版本:

git checkout 5246252
npm run electron:build

electronMain.js里面的所有console.log()都显示在终端(命令行)window(不是开发者工具控制台)

要触发快速查看功能:

要触发下载事件,您只需打开“导航器”页面并从互联网上拖放任何文件(或网站 URL)即可。它会触发错误的 will-download 事件处理程序(quickView window 的处理程序),您应该会看到控制台消息。

包含此 Web 视图的快速视图 window 是在 app.ready 事件上创建的。指定分区时,将在创建 quickView window 后立即弹出:

https://github.com/aleksey-hoffman/sigma-file-manager/blob/47ce65bdac78e5c9b17315f16623d40d81dcf1bb/src/electronMain.js#L698

更新:

较小的复制示例:

我能够用这段代码重现它:

let window1 = null
let window2 = null

electron.app.on('ready', async () => {
  createWindow1()
  createWindow2()

  setTimeout(() => {
    console.log('trigger window 1 download')
    window1.webContents.downloadURL('https://whosebug.com')
  }, 1000)
})


function createWindow2 () {
  window1.webContents.session.once('will-download', downloadHandler1)
  window2.webContents.session.once('will-download', downloadHandler2)
}

function createWindow1 () {
  window1 = new electron.BrowserWindow()
  window1.loadURL('app://./quickViewWindow.html')
  window1.webContents.session.once('will-download', downloadHandler1)
}

function createWindow2 () {
  window2 = new electron.BrowserWindow()
  window2.loadURL('app://./quickViewWindow.html')
  window2.webContents.session.once('will-download', downloadHandler2)
}

function downloadHandler1 (event, item, webContents) {
  console.log('window will-download handler 1')
}

function downloadHandler2 (event, item, webContents) {
  console.log('window will-download handler 2')
}

setTimeout 运行时,我看到以下 console.log() 消息:

trigger window 1 download
window will-download handler 1
window will-download handler 2

从日志中可以看出,will-download事件触发了windows

两者的事件处理程序

如果我为每个 window 指定一个单独的分区,共享事件处理程序的问题得到解决,但我遇到了上面提到的第二个问题 - link 关联在启动时弹出

window1 = new electron.BrowserWindow({
  webPreferences: {
    partition: 'partition1',
  }
})
window2 = new electron.BrowserWindow({
  webPreferences: {
    partition: 'partition2',
  }
})

我明白了。如果这样做有误,请有人告诉我。

这是我修复它的方法:

修复问题 #1:

为 window 设置自定义分区名称,因此它使用自己的 webContents.session 而不是共享默认分区。

主要流程:

windows.quickViewWindow = new electron.BrowserWindow({
  ...
  webPreferences: {
    partition: 'quickView',

...

windows.quickViewWindow.webContents.session.once(
  'will-download',
  (event, item, webContents) => {
    event.preventDefault()
    ...
  }
)

quickViewWindow.html:

ipcRenderer.on('load:webview', (event, data) => {
  ...
  webviewNode.setAttribute('partition', 'quickView')

修复问题 #2:

在 window URL 的生产路径中设置 file:// 协议:

productionPath = `file://${__static}/quickViewWindow.html`

这是提交:https://github.com/aleksey-hoffman/sigma-file-manager/commit/31208809cda7614a7c2f32237ae14f6c9c602f8f