网络视图中的 Polyfill window.showModalDialog

Polyfill window.showModalDialog in webview

所以我正在创建一个带有嵌入式 <webview> 元素的 Chrome 应用程序。嵌入式 webapp 包含许多遗留代码,例如 window.showModalDialog 调用(Chrome 不再支持)。

我现在要做的是填充这些调用。我创建了一个简单的测试示例:

<webview src="http://legacyCodeIsAwesome.com/" style="width:100%; height:100%"></webview>

在webview元素上运行的代码:

webview.addEventListener('contentload', function() {
    webview.executeScript(
      {
        code: 'window.showModalDialog = function() { console.log ("Hello, world");}',
        runAt: 'document_start'
      }
    );
  });

以上代码运行(添加调试 console.log 有效),只是它没有执行它应该执行的操作,即覆盖 showModalDialog 函数。

在 webviews 中覆盖 window 对象的函数是否有某种限制?有解决办法吗?

当您调用 webview.executeScript 时,您实际上创建了一个 Content Script

内容脚本的核心原则之一是 isolated world:内容脚本看到 window 对象的单独副本。

Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.

因此,您的覆盖有效,但仅在内容脚本上下文中有效。

要在页面上下文本身中执行覆盖,我们需要更深入

内容脚本可以在页面上创建 <script> 元素;所述元素中的代码将在页面的上下文中执行。您可以阅读此技术,称为页面级脚本或注入脚本,in this canonical question

// Content script
var script = document.createElement('script');
script.textContent = `
  window.showModalDialog = function() {
    console.log("Hello, world");
  }
`;
(document.head||document.documentElement).appendChild(script);
script.remove();

就是说,您注入代码的时间太晚了。在 contentload 上,有问题的 JS 可能已经执行,添加 "document_start" 不会倒带时间。

幸运的是,你可以declare in advance the content scripts you want to have:

webview.addContentScripts([
  {
    name: "showModalDialogPolyfill",
    matches: ["https://webapp.example.com/*"],
    js: { files: ['content.js'] },
    run_at: 'document_start'
  }
]);
webview.src = "https://webapp.example.com/";