[electron]Webview 预加载脚本无法在 webview src 更改中幸存

2024-05-11 587 views
5

我在问题主题中提到了 0.27.2,但对我来说它在 0.23 之后就崩溃了。我需要在这里进行健全性检查。我正在使用我的应用程序主窗口和 Web 视图执行一个非常基本的 ping/pong 类型 IPC。这对我来说在 0.23.0 版本上工作得很好,但在 0.24.0 版本上中断,一直到今天的 0.27.2 版本。我查看了 webview 的开发工具,可以看出我的预加载脚本正在运行,但执行任何 IPC 发送都不会发送到 webview。

相同的代码在 0.23.0 中工作正常,但在 0.24 -> 0.27.2 中中断。

我正在做与以下列出的完全相同的非常基本的 IPC:

https://github.com/atom/electron/blob/master/docs/api/web-view-tag.md#ipc-message

// In embedder page.
webview.addEventListener('ipc-message', function(event) {
  console.log(event.channel);
  // Prints "pong"
});
webview.send('ping');

.....

// In guest page.
var ipc = require('ipc');
ipc.on('ping', function() {
  ipc.sendToHost('pong');
})

还有其他人在 webview 中遇到 IPC 问题吗?

回答

1

这在 Slack 应用程序中对我们有用,但我们一直必须做的一件事是将变量修补process回 via process.nextTick

  const processRef = global.process;
  process.nextTick(function() { global.process = processRef; });
6

感谢那!我能够使用基本的乒乓球运行一个小样本。我认为我的问题是当设置webview IPC的src时没有响应。这是我目前的理论,我将尝试我的小测试应用程序,看看 IPC 在更改 src 后是否仍然存在。

5

是的,src 更改后 IPC 停止工作。或者更确切地说,在我的预加载中设置的代码不再可以运行。

7

这是一个演示该行为的小示例。

https://github.com/frankhale/electron-webview-ipc-test

当该示例运行时,它会在 Web 视图中打开一个网站,启动 ping/pong 消息并将它们记录到主窗口和 Web 视图上的开发工具中的控制台。 10 秒后,src 更改为另一个网站。 webview节点上下文被重置?预加载脚本代码消失了,IPC 不再工作。

我只是想强调 0.23 版本可以工作并且 IPC 在 webview src 更改后仍然存在。 Electron 0.24 及更新版本均失败。

以下问题也可能相关:#1823 另一个可能的相关问题:#1820 还有另一个(当当!)#1754

在我的特定情况下,我没有使用节点集成。有趣的是,改变 src 会让事情变得更加糟糕。我现在正在研究代码,看看是否可以看到 webview 可能发生的任何变化。

6

谢谢你!!

4

@frankhale 您尝试过最新版本的二进制文件(电子 v0.27.3)吗?我发现preload属性还是不能正常使用。步骤如下:

  1. 创建一个 webview html 元素,src 为“about:blank”。然后将src更改为url。有用。
  2. 再次创建一个新的webview html元素,src为'about:blank'。然后将src更改为步骤1的url。这不起作用。
  3. 再次创建一个新的webview html元素,src为'about:blank'。然后将 src 更改为新的 url(与步骤 1 不同)。这不起作用。

另外,我已经尝试过这些步骤:

  1. 创建一个webview html元素,src是一个url。有用。
  2. 创建一个新的webview html元素,src与步骤1相同。它不起作用。
  3. 创建一个新的webview html元素,src与步骤1不同。它不起作用。

@zcbenz 请在有空时帮助检查步骤。

谢谢!

8

@zcbenz 在我尝试了更多之后,我发现如果你将 src 更改为不同的站点(换句话说,不同的域),它就可以工作。然后,如果我再次将src更改为站点中的页面,则不起作用。

9

@steem,我还没有尝试过 0.27.3,但我确实从 master 编译并正在使用修复程序。我没有看到任何关于预加载补丁 #1850 的奇怪问题,因为我只创建一个 webview 并在整个应用程序生命周期中重用它。在这种特殊情况下,它似乎对我来说效果很好。

2

@frankhale @zcbenz 我今天尝试了一个 webview,在更改 src 两次后仍然无法工作(注意:src 是相同的)。我也尝试过重新加载方法,它只在第一次有效。我的测试js代码很简单:

var site_count = 0;
function preload_test() {
    console.log('----------------: ' + site_count);
    ++site_count;
}
setInterval(preload_test, 3000);

使用“console-message”事件来回显消息。

3

@steem 将 src 更改为相同的值将被忽略,如果您想要刷新,您应该调用reload.

2

@zcbenz 是的,我使用重新加载,但仍然不起作用:(

1

你能举个例子吗?以下代码对我有用:

/tmp/test.js:

require('ipc').sendToHost('test');

在开发工具中:

var w = new WebView;
w.setAttribute('preload', 'file:///tmp/test.js');
w.addEventListener('ipc-message', function(event) {
  console.log(event.channel);
});
w.src = 'http://google.com';
document.body.appendChild(w);
2

@zcbenz 这是示例代码:

HTML:

<html>
    <head>
        <meta charset="utf-8">
        <title>Test</title>
    </head>
    <body>
      <input type="button" id="test_refresh" value="refresh"><br>
      <input type="button" id="test_change_src" value="change src">&nbsp;<input type="text" id="new_url" value=""><br>
      <script src="js/deps/jquery-2.0.3.min.js"></script>
      <script>
      function create_web_view (id, url) {
        $(document.body).append('<webview autosize="on" id="' + id + '" src="' + url + '"  preload="op/op_min.js" plugins></webview>');
      }
      create_web_view('test1', 'http://www.baidu.com');
      $('#test_change_src').click(function(){
        document.getElementById('test1').src = $('#new_url').val();
      });
      $('#test_refresh').click(function(){
        document.getElementById('test1').reload();
      });
      document.getElementById('test1').addEventListener('console-message', function(e) {
        console.log('webview message: ' + e.message);
      });
      </script>
    </body>
</html>

op_min.js

var site_count = 0;
function preload_test() {
    console.log('----------------: ' + site_count);
    ++site_count;
}
setInterval(preload_test, 3000);

如果单击刷新按钮,op_min.js 仅在前两次单击时起作用。

我发现你使用绝对路径进行预加载,我会再试一次并给你结果。

更新:如果使用绝对路径进行预加载,问题仍然存在。

5

@zcbenz 我调试了代码,发现它可能是由v8引擎引起的。第一次调用 reload 将导致 AtomBrowserClient::AppendExtraCommandLineSwitches 被调用。但如果再次调用 reload,AtomBrowserClient::AppendExtraCommandLineSwitches 将不会被调用。每次调用reload时都会调用WebContents::LoadURL。 v8 代码是 libchromiumcontent,我在哪里可以获取代码并构建它?

更新:似乎 libchromiumcontent 代码在这里:https://github.com/atom/libchromiumcontent。我会尝试构建它。

3

@zcbenz @frankhale 最后,我发现它是由以下行引起的: app.commandLine.appendSwitch('process-per-site');

我删除后就可以了。如果没有,调用一次reload后,就不起作用了。即使您创建一个新的 webview,并将 src 初始化为网站的任何页面,但一次后它就不起作用了。

因此,在某些情况下,如果处于“每个站点进程”模式,libchromiumcontent 可能不会调用 AtomBrowserClient::AppendExtraCommandLineSwitches。目前,我没有时间调试 libchromiumcontent。 @zcbenz,如果您有空,请帮忙查看一下。

谢谢!

4

@steem 感谢您调试这个!抱歉我没有时间去研究它。

在 Electron 中,每个页面都被迫使用自己的进程,这是节点集成支持所必需的,因此,如果您传递process-per-site给 Chromium,某些页面将被迫共享相同的进程,并且节点集成将不适用于它们。

5

我使用的是 0.26.0,一旦我更改 src,或导航到另一个域,我就会丢失预加载的脚本。这个问题在0.26.0中还没有解决吗?

8

@zcbenz 好的,我明白了。

如果达到最大进程数,Chromium 进程模型将不会创建新进程。只需担心达到最大进程数后是否会出现此问题。

1

我在 0.26.0 时问题仍然存在。

7

适用于 0.28.0 :+1:

5

@mschnee 您使用的是哪个操作系统?你能在 0.32.0 上重现吗?

2

@zcbenz 已验证可在 Windows 10、OSX 10.10 和 Linux(gentoo x64、vanilla kernel 4.2)上的 electro-prebuilt@0.32.1 中工作

抱歉,我杀死了一只虫子,看来你比我先一步了!