WebView2 DevToolsProtocolEvent未触发

6

我正在尝试创建一个应用程序,该应用程序使用WebView2 WPF组件。目前我正在处理通过 console.log() 写入的网站 JavaScript 代码的消息和错误日志记录。

这是我当前拥有的:

public partial class WebView2BrowserControl : WebView2
{
    private async void OnWebViewLoaded(object sender, RoutedEventArgs e)
    {
        await EnsureCoreWebView2Async();
        if (showDeveloperTools)
        {
            CoreWebView2.GetDevToolsProtocolEventReceiver("Log.entryAdded").DevToolsProtocolEventReceived += OnConsoleMessage;
            CoreWebView2.OpenDevToolsWindow();
        }
        else
        {
            CoreWebView2.Settings.AreDevToolsEnabled = false;
        }
    }

    private void OnConsoleMessage(object sender, CoreWebView2DevToolsProtocolEventReceivedEventArgs e)
    {
        if (e != null && e.ParameterObjectAsJson != null)
        {
            Trace.WriteLine("WebView2:" + e.ParameterObjectAsJson);
        }
    }
}

如您所见,我正在使用GetDevToolsProtocolEventReceiver方法订阅DevTools中的事件。文档中说明如下:

eventName:String - 事件的完整名称,格式为 {domain}.{event}。 有关 DevToolsProtocol 事件描述和事件参数的更多信息,请转到 DevTools Protocol Viewer。

... 根据 DevTools 协议查看器,我要查找的事件是Log.entryAdded

现在的问题是,虽然调用GetDevToolsProtocolEventReceiver("Log.entryAdded")没有抛出任何异常,但该事件从未被触发,即使我可以在DevTools中看到正在记录的内容。我甚至尝试在 DevTools 窗口中编写自己的 console.log()调用。

其他我尝试过的事情:

  • 使用安装 WebView2 的 Evergreen Standalone Installer 或 Fixed Version(87 和 88 版本均可,后者基本上是一个便携版的 WebView2)
  • 使用来自 NuGet 的最新稳定版本的 Microsoft.Web.View2.Core.dll,即 1.0.705.50 和最新的预发布版本
  • 同时使用 Log.entryAdded事件和 Console.messageAdded(已弃用)
  • 在打开 DevTools 窗口后订阅事件

所以我错在哪里了?


是的,它被设置为true,因为DevTools窗口打开了,并且我还通过调试器检查了if语句中的代码是否运行。 - Norberth Csorba
2个回答

6

你已经接近成功了!

原来,你需要“启用”协议事件,否则它将不会被调用。

只需在添加事件监听器后启用它,像这样:

CoreWebView2.GetDevToolsProtocolEventReceiver("Log.entryAdded").DevToolsProtocolEventReceived += ConsoleMessage;
await CoreWebView2.CallDevToolsProtocolMethodAsync("Log.enable", "{}");

现在您应该会在跟踪中收到消息。

Windows窗体的替代方案(在安装并将WebView2放置在表单上之后:

private async void Form1_Load(object sender, EventArgs e)
{
    await webView21.EnsureCoreWebView2Async();
}

private async void WebView21_CoreWebView2InitializationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e)
{
    webView21.CoreWebView2.GetDevToolsProtocolEventReceiver("Log.entryAdded").DevToolsProtocolEventReceived += ConsoleMessage;
    await webView21.CoreWebView2.CallDevToolsProtocolMethodAsync("Log.enable", "{}");
    webView21.CoreWebView2.OpenDevToolsWindow();
    webView21.CoreWebView2.Navigate("https://stackoverflow.com");

}

private void ConsoleMessage(object sender, Microsoft.Web.WebView2.Core.CoreWebView2DevToolsProtocolEventReceivedEventArgs e)
{
    if (e != null && e.ParameterObjectAsJson != null)
    {
        Console.WriteLine("WebView2:" + e.ParameterObjectAsJson);
    }
}

就是这样!谢谢!似乎还有另一件事情阻止我接收事件,那就是我在页面中使用了一些iframe。对于stackoverflow.com,您的解决方案有效,但对于某些包含iframe的页面则无效。您知道如何告诉WebView2:“嘿,我想加载页面x,但要监听内部iframe的DevTools事件”吗? - Norberth Csorba
3
使用已弃用的控制台域似乎可以解决先前评论中描述的问题。 - Norberth Csorba
很高兴你找到了一个可行的解决方案。愉快编码! - Poul Bak

1

我试了被接受的答案,但没有用。

它使用了 Log 领域来实现,这是用于记录 chromium 日志消息的。

我必须使用 Runtime 领域,这使我能够访问 console.log。

主要代码:

        async void InitializeAsync()
        {
            await webView.EnsureCoreWebView2Async(null);
            DevToolsProtocolHelper helper = webView.CoreWebView2.GetDevToolsProtocolHelper();
            await helper.Runtime.EnableAsync();
            helper.Runtime.ConsoleAPICalled += Runtime_ConsoleAPICalled;
        }

        private void Runtime_ConsoleAPICalled(object sender, Runtime.ConsoleAPICalledEventArgs e)
        {
            String test = e.Args[0].Value.ToString();
            Trace.WriteLine(test);
        }

DevTools协议没有任何更改,OP使用的是日志域,需要启用它,而您正在使用运行时域,因此需要显式启用它。每个域都有自己的启用方法。https://chromedevtools.github.io/devtools-protocol/tot/Runtime/ - amaitland
我尝试了已接受答案中的代码,但它无效。已接受答案中有 Log.enable,所以我不知道为什么它不起作用。如果有人遇到相同的问题,也许可以尝试运行时。 - justadev
这个问题最初是关于日志域的,因此答案是针对该特定领域的。我的观点是,您希望运行时域的事件触发您调用Runtime.enable,就像您调用Network.enable以触发来自网络域的事件一样。您在猜测DevTools协议发生了变化,我告诉您这是不正确的,没有任何变化。 - amaitland
原帖作者想要获取console.log(就像我一样)。他在文档中读到应该从Log domain 中获取它。就像我说的,我尝试了一下,但在Log domain 上没能奏效。我同意我的API变更评论有些不妥,因为我没有相关信息。如果您认为这样更好,我可以将该评论删除。我添加回答的主要原因是Runtime有效而Log则无效,我认为这可能会对未来的其他人有所帮助。 - justadev
两个答案都需要一些澄清,日志域不是用于控制台日志记录,而是用于Chromium日志消息。因此,访问控制台日志的方法是正确的,简化你的答案。 - amaitland
更新了,感谢解释。 - justadev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接