Browser

本指南将介绍如何创建、使用和关闭 Browser

有关 DotNetBrowser 架构、其主要组件及其交互的更多信息,请参阅架构指南。

创建浏览器

要创建一个新的 IBrowser 示例,使用 IProfile.CreateBrowser() 方法。 例如:

IBrowser browser = engine.Profiles.Default.CreateBrowser();
Dim browser As IBrowser = engine.Profiles.Default.CreateBrowser()

如果您使用 IEngine.CreateBrowser() 方法,那么浏览器将会在默认配置文件下创建。 然而,这种方法已经过时了,建议改用相应的配置文件实例来代替。

此方法执行以下操作:

  1. 创建一个新的 IBrowser 示例。
  2. 在其中加载 about:blank 网页并等待网页完全加载。

处理浏览器

IBrowser 实例在 Chromium Main 进程中运行,并分配要释放的内存和系统资源。 当不再需要 IBrowser 实例时,使用 IBrowser.Dispose() 方法处理它。 因此,所有分配的内存和系统资源都将被释放。 请参阅以下代码示例:

IBrowser browser = engine.Profiles.Default.CreateBrowser();
// ...
browser.Dispose();
Dim browser As IBrowser = engine.Profiles.Default.CreateBrowser()
' ...
browser.Dispose()

尝试使用已处理的 IBrowser 实例会导致 ObjectDisposedException

在下列情况下,IBrowser实例将自动释放:

  1. 当其父 IEngine 实例被意外处理或崩溃时。
  2. 当此 IBrowser 实例是一个 弹出窗口,并使用 window.close() 从 JavaScript 关闭时。

使用 Disposed 事件可在 IBrowser 实例被处理时收到通知。 请参阅以下代码示例:

browser.Disposed += (sender, event => {});
AddHandler browser.Disposed,  Sub(s,e)
End Sub

使用 IsDisposed 属性检查 IBrowser 是否已被处理:

bool disposed = browser.IsDisposed;
Dim disposed As Boolean = browser.IsDisposed

浏览器大小

默认情况下,IBrowser 大小为空。 如果要在网页上使用 DOM查找文本,请先设置浏览器大小。

要更新 IBrowser 的大小,请使用其 Size 属性。 请参阅以下代码示例:

browser.Size = new Size(800, 600);
browser.Size = New Size(800, 600)

此方法通知 Chromium IBrowser 实例的大小已更改。 Chromium 将异步更新加载的网页的 DOM 布局并重新绘制其内容。 设置该属性后,可能需要一些时间才能重新绘制网页。

浏览器设置

可以通过 IBrowser.Settings 属性自定义浏览器设置。 浏览器设置可用于禁用浏览器中的图像、插件或 JavaScript、隐藏滚动条、禁用应用程序缓存。 请参阅以下代码示例:

// 禁用所有脚本。
browser.Settings.JavaScriptEnabled = false;
' 禁用所有脚本。
browser.Settings.JavaScriptEnabled = False

指定 WebRTC IP 处理策略

DotNetBrowser 允许自定义 WebRTC IP 处理策略。 这些是 DotNetBrowser 中可用的 WebRTC 策略:

  • Default - Chromium 的默认行为。 设置此策略后,WebRTC 可以枚举所有接口并将它们绑定以发现公共接口。

  • DefaultPublicInterfacesOnly - 告知浏览器使用默认的公共网络适配器发送 WebRTC 流量。 这将是系统-VPN 用户的 VPN 适配器。 WebRTC 必须只使用 http 使用的默认路由。

  • DefaultPublicAndPrivateInterfaces- 与DefaultPublicInterfacesOnly 相同,但它还允许 WebRTC 流量通过默认专用接口传输到本地网络。

  • DisableNonProxiedUdp - 禁用非代理 UDP 并强制代理。 此策略强制使用代理,并且仅允许通过 UDP 代理传输 WebRTC 流量。 根据 UDP 代理的使用情况,它能有效地禁用大多数用户的 WebRTC 通信。

以下示例代码演示了如何为浏览器实例配置 WebRTC IP 处理策略:

browser.Settings.WebRtcIpHandlingPolicy = 
    WebRtcIpHandlingPolicy.DisableNonProxiedUdp;
browser.Settings.WebRtcIpHandlingPolicy = 
    WebRtcIpHandlingPolicy.DisableNonProxiedUdp

深色模式

您可以在网页上强制使用首选配色方案,如下所示:

// 强制启用深色模式。
browser.Settings.PreferredColorScheme = PreferredColorScheme.Dark;
// 强制启用浅色模式。
browser.Settings.PreferredColorScheme = PreferredColorScheme.Light;
' 强制启用深色模式。
browser.Settings.PreferredColorScheme = PreferredColorScheme.Dark;
// 强制启用浅色模式。
browser.Settings.PreferredColorScheme = PreferredColorScheme.Light 

上述设置仅适用于尊重 prefers-color-scheme 媒体查询的网站。

用户代理

您可以覆盖默认的用户代理字符串,并将 IBrowser 配置为使用自定义字符串。 请参阅以下代码示例:

browser.UserAgent = "<user-agent>";
browser.UserAgent = "<user-agent>"

相同的属性可用于获取当前用户代理字符串:

string userAgent = browser.UserAgent;
Dim userAgent As String = browser.UserAgent

远程调试 URL

要获取在特定 IBrowser 实例中加载的网页的远程调试 URL,请使用以下方法:

string url = browser.DevTools.RemoteDebuggingUrl;
Dim url As String = browser.DevTools.RemoteDebuggingUrl

仅当 IEngine 配置有远程调试端口时,此方法才会返回有效的 URL。 否则,属性值为空。

DevTools

要在不配置远程调试端口的情况下以编程方式显示 DevTools 窗口,请使用以下代码:

browser.DevTools.Show();
browser.DevTools.Show()

DevTools

查看页面源代码

您可以使用以下方法查看已加载网页或框架的源代码:

browser.MainFrame?.ViewSource();
browser.MainFrame?.ViewSource()

上面的代码告诉 Chromium 使用主框架的 HTML 源代码创建并打开一个弹出窗口。

Page source

鼠标和键盘事件

DotNetBrowser 允许使用以下处理程序在鼠标和键盘事件发送到网页之前拦截它们:

  • IBrowser.Mouse.Entered.Handler
  • IBrowser.Mouse.Exited.Handler
  • IBrowser.Mouse.Pressed.Handler
  • IBrowser.Mouse.Released.Handler
  • IBrowser.Mouse.Moved.Handler
  • IBrowser.Mouse.WheelMoved.Handler
  • IBrowser.Keyboard.KeyPressed.Handler
  • IBrowser.Keyboard.KeyTyped.Handler
  • IBrowser.Keyboard.KeyReleased.Handler

以下代码示例演示了如何抑制鼠标滚轮事件:

browser.Mouse.WheelMoved.Handler = 
    new Handler<IMouseWheelMovedEventArgs, InputEventResponse>(e =>
    {
        return InputEventResponse.Suppress;
    });
browser.Mouse.WheelMoved.Handler = 
    New Handler(Of IMouseWheelMovedEventArgs, InputEventResponse)(Function(e)
        Return InputEventResponse.Suppress
    End Function)

您可以使用这些处理程序获取有关鼠标和键盘事件的通知,从而在应用程序中实现热键。 您还可以抑制默认快捷方式,如 Ctrl+C。 请参阅以下代码示例:

browser.Keyboard.KeyPressed.Handler = 
    new Handler<IKeyPressedEventArgs, InputEventResponse>(e =>
    {
        bool keyCodeC = e.VirtualKey == KeyCode.VkC;
        bool controlDown = e.Modifiers.ControlDown;
        if (controlDown && keyCodeC) 
        {
            return InputEventResponse.Suppress;
        }
        return InputEventResponse.Proceed;
    });
browser.Keyboard.KeyPressed.Handler = 
    New Handler(Of IKeyPressedEventArgs, InputEventResponse)(Function(e)
        Dim keyCodeC As Boolean = e.VirtualKey = KeyCode.VkC
        Dim controlDown As Boolean = e.Modifiers.ControlDown
        If controlDown AndAlso keyCodeC Then
            Return InputEventResponse.Suppress
        End If
        Return InputEventResponse.Proceed
    End Function)

模拟用户输入

DotNetBrowser 允许模拟鼠标和键盘输入。 模拟在 WPF 和 Windows 窗体的离屏和硬件加速渲染模式下都可用。

您可以通过引发鼠标和键盘事件来模拟输入。 例如,下面是模拟打字的方法:

private static void SimulateKey(IKeyboard keyboard, KeyCode key, string keyChar,
                                KeyModifiers modifiers = null)
{
    modifiers = modifiers ?? new KeyModifiers();
    KeyPressedEventArgs keyDownEventArgs = new KeyPressedEventArgs
    {
        KeyChar = keyChar,
        VirtualKey = key,
        Modifiers = modifiers
    };

    KeyTypedEventArgs keyPressEventArgs = new KeyTypedEventArgs
    {
        KeyChar = keyChar,
        VirtualKey = key,
        Modifiers = modifiers
    };
    KeyReleasedEventArgs keyUpEventArgs = new KeyReleasedEventArgs
    {
        VirtualKey = key,
        Modifiers = modifiers
    };

    keyboard.KeyPressed.Raise(keyDownEventArgs);
    keyboard.KeyTyped.Raise(keyPressEventArgs);
    keyboard.KeyReleased.Raise(keyUpEventArgs);
}
Private Shared Sub SimulateKey(keyboard As IKeyboard, key As KeyCode, keyChar As String,
                               Optional modifiers As KeyModifiers = Nothing)
    modifiers = If(modifiers, New KeyModifiers())
    Dim keyPressedEventArgs = New KeyPressedEventArgs With {
        .KeyChar = keyChar,
        .VirtualKey = key,
        .Modifiers = modifiers
    }

    Dim keyTypedEventArgs = New KeyTypedEventArgs With {
        .KeyChar = keyChar,
        .VirtualKey = key,
        .Modifiers = modifiers
    }
        
    Dim keyReleasedEventArgs = New KeyReleasedEventArgs With {
        .VirtualKey = key,
        .Modifiers = modifiers
    }

    keyboard.KeyPressed.Raise(keyPressedEventArgs)
    keyboard.KeyTyped.Raise(keyTypedEventArgs)
    keyboard.KeyReleased.Raise(keyReleasedEventArgs)
End Sub
IKeyboard keyboard = browser.Keyboard;
SimulateKey(keyboard, KeyCode.VkH, "H");
SimulateKey(keyboard, KeyCode.VkE, "e");
SimulateKey(keyboard, KeyCode.VkL, "l");
SimulateKey(keyboard, KeyCode.VkL, "l");
SimulateKey(keyboard, KeyCode.VkO, "o");
SimulateKey(keyboard, KeyCode.Space, " ");
// 模拟一些非字母字符的输入。
SimulateKey(keyboard, KeyCode.Vk5, "%", new KeyModifiers {ShiftDown = true});
SimulateKey(keyboard, KeyCode.Vk2, "@", new KeyModifiers {ShiftDown = true});
Dim keyboard As IKeyboard = browser.Keyboard
SimulateKey(keyboard, KeyCode.VkH, "H")
SimulateKey(keyboard, KeyCode.VkE, "e")
SimulateKey(keyboard, KeyCode.VkL, "l")
SimulateKey(keyboard, KeyCode.VkL, "l")
SimulateKey(keyboard, KeyCode.VkO, "o")
SimulateKey(keyboard, KeyCode.Space, " ")
' 模拟一些非字母字符的输入。
SimulateKey(keyboard, KeyCode.Vk5, "%",
            New KeyModifiers() With {.ShiftDown = True})
SimulateKey(keyboard, KeyCode.Vk2, "@",
            New KeyModifiers() With {.ShiftDown = True})

我们的存储库中提供了完整的示例:

WinForms (C#, VB.NET)
WPF (C#, VB.NET)

您可以通过依次引发 IMouse.MovedIMouse.PressedIMouse.Released 事件来模拟鼠标单击。 例如,下面是模拟单击的方法:

IMouse mouse = browser.Mouse;
MouseButton mouseButton = MouseButton.Left;
Point location = new Point(10, 10);

MouseMovedEventArgs moveEvent = new MouseMovedEventArgs
{
    Location = location
};

MousePressedEventArgs pressEvent = new MousePressedEventArgs
{
    Location = location,
    Button = mouseButton,
    ClickCount = 1
};

MouseReleasedEventArgs releaseEvent = new MouseReleasedEventArgs
{
    Button = mouseButton,
    ClickCount = 1,
    Location = location
};

mouse.Moved.Raise(moveEvent);
Thread.Sleep(200);
mouse.Pressed.Raise(pressEvent);
Thread.Sleep(200);
mouse.Released.Raise(releaseEvent);
Dim mouse As IMouse = browser.Mouse
Dim mouseButton As MouseButton = MouseButton.Left
Dim location As New Point(10, 10)

Dim moveEvent As New MouseMovedEventArgs With {.Location = location}

Dim pressEvent As New MousePressedEventArgs With {
    .Location = location,
    .Button = mouseButton,
    .ClickCount = 1
}

Dim releaseEvent As New MouseReleasedEventArgs With {
    .Button = mouseButton,
    .ClickCount = 1,
    .Location = location
}

mouse.Moved.Raise(moveEvent)
Thread.Sleep(200)
mouse.Pressed.Raise(pressEvent)
Thread.Sleep(200)
mouse.Released.Raise(releaseEvent)

WebRTC 屏幕共享

Chromium 提供了允许共享整个屏幕、应用程序窗口或网页的内置功能。 默认情况下,DotNetBrowser 会显示一个标准对话框,供用户选择捕获源:

WebRTC

如果不想显示此对话框,可以通过编程方式处理请求和选择捕获源。 例如:

browser.Capture.StartSessionHandler = 
    new Handler<StartSessionParameters, StartSessionResponse>(p =>
{
    // 告诉浏览器实例启动新的捕获会话,并指定
    // 捕获源。
    return StartSessionResponse.SelectSource(p.Sources.Screens.FirstOrDefault(),
                                             AudioMode.Ignore);
});
browser.Capture.StartSessionHandler = 
    New Handler(Of StartSessionParameters, StartSessionResponse)(Function(p)
        ' 告诉浏览器实例启动新的捕获会话,并指定
        ' 捕获源。
    Return StartSessionResponse.SelectSource(p.Sources.Screens.FirstOrDefault(),
                                            AudioMode.Ignore)
End Function)

要以编程方式停止会话,请使用以下方法:

// 获取当前浏览器的所有捕获会话。
IReadOnlyList<ISession> sessions = browser.Capture.Sessions;
foreach (ISession session in sessions)
{
    string sourceName = session.Source.Name;
    bool isActive = session.IsActive;

    // 停止会话。
    session.Stop();
}
' 获取当前浏览器的所有捕获会话。
Dim sessions As IReadOnlyList(Of ISession) = browser.Capture.Sessions
For Each session As ISession In sessions
    Dim sourceName As String = session.Source.Name
    Dim isActive As Boolean = session.IsActive

    ' 停止会话。
    session.Stop()
Next 

您还可以禁止显示屏幕共享请求和标准对话框。 这是示例:

browser.Capture.StartSessionHandler =
    new Handler<StartSessionParameters, StartSessionResponse>(p =>
{
    // 取消共享操作。
    return StartSessionResponse.Cancel();
});
browser.Capture.StartSessionHandler = 
    New Handler(Of StartSessionParameters, StartSessionResponse)(Function(p)
        ' 取消共享操作。
    Return StartSessionResponse.Cancel()
End Function)

拖放

自 DotNetBrowser 2.3 起,可以在硬件加速渲染模式下拦截网页上的拖入和拖出事件。 为此,您需要使用 EnterDragHandlerDropHandler。 例如:

browser.DragAndDrop.EnterDragHandler =
    new Handler<EnterDragParameters>(OnDragEnter);
browser.DragAndDrop.DropHandler = new Handler<DropParameters>(OnDrop);
browser.DragAndDrop.EnterDragHandler =
    New Handler(Of EnterDragParameters)(AddressOf OnDragEnter)
browser.DragAndDrop.DropHandler = New Handler(Of DropParameters)(AddressOf OnDrop)
private void OnDragEnter(EnterDragParameters arg)
{
    if (arg.Event.DropData != null)
    {
        //将文件名写入调试输出。
        foreach (IFileValue file in arg.Event.DropData.Files)
        {
            Debug.WriteLine($"OnDragEnter: File = {file?.FileName}");
        }
    }
}

private void OnDrop(DropParameters arg)
{
    if (arg.Event.DropData != null)
    {
        //将文件名写入调试输出。
        foreach (IFileValue file in arg.Event.DropData.Files)
        {
            Debug.WriteLine($"OnDrop: File = {file?.FileName}");
        }
    }
}
Private Sub OnDragEnter(arg As EnterDragParameters)
    If arg.Event.DropData IsNot Nothing Then
        ' 将文件名写入调试输出。
        For Each file As IFileValue In arg.Event.DropData.Files
            Debug.WriteLine($"OnDragEnter: File = {file?.FileName}")
        Next file
    End If
End Sub

Private Sub OnDrop(arg As DropParameters)
    If arg.Event.DropData IsNot Nothing Then
        ' 将文件名写入调试输出。
        For Each file As IFileValue In arg.Event.DropData.Files
            Debug.WriteLine($"OnDrop: File = {file?.FileName}")
        Next file
    End If
End Sub

在 .NET Framework 中,还可以在这些处理程序的作用范围内使用 IDataObject 实例来接收和处理拖放数据的 Windows 特定表示形式。 如果指定了 --enable-com-in-drag-drop Chromium switch,该功能就会可用。 例如:

private void OnDragEnter(EnterDragParameters arg)
{
    LogData(arg.Event.DropData, nameof(OnDragEnter));
    Debug.WriteLine($"Data is null? {(arg.Event.DataObject == null)}");

    System.Runtime.InteropServices.ComTypes.IDataObject dataObject =
        arg.Event.DataObject;
    if (dataObject != null)
    {
        // 处理 IDataObject 中的数据
        ExtractData(nameof(OnDragEnter), new DataObject(dataObject));
    }
}

private void OnDrop(DropParameters arg)
{
    LogData(arg.Event.DropData, nameof(OnDrop));
    Debug.WriteLine($"Data is null? {(arg.Event.DataObject == null)}");

    System.Runtime.InteropServices.ComTypes.IDataObject dataObject =
        arg.Event.DataObject;
    if (dataObject != null)
    {
        // 处理 IDataObject 中的数据
        ExtractData(nameof(OnDrop), new DataObject(dataObject));
    }
}
Private Sub OnDragEnter(arg As EnterDragParameters)
    LogData(arg.Event.DropData, NameOf(OnDragEnter))
    Debug.WriteLine($"Data is null? {(arg.Event.DataObject Is Nothing)}")
    Dim dataObject As IDataObject = arg.Event.DataObject

    If dataObject IsNot Nothing Then
        ' 处理 IDataObject中的数据。
        ExtractData(NameOf(OnDragEnter), New DataObject(dataObject))
    End If
End Sub

Private Sub OnDrop(arg As DropParameters)
    LogData(arg.Event.DropData, NameOf(OnDrop))
    Debug.WriteLine($"Data is null? {(arg.Event.DataObject Is Nothing)}")
    Dim dataObject As IDataObject = arg.Event.DataObject

    If dataObject IsNot Nothing Then
        ' 处理 IDataObject 中的数据。
        ExtractData(NameOf(OnDrop), New DataObject(dataObject))
    End If
End Sub

如需完整示例,请导航至我们的存储库: C#, VB.NET.

在离屏渲染模式下,不支持拖放操作,并且已完全禁用。

标题事件

TitleChanged 事件表示主框架中文档的标题已更改。

要在文档标题更改时获得通知,请使用 TitleChanged 监听器,如下面的代码示例所示:

browser.TitleChanged += delegate (object sender, TitleChangedEventArgs e)
{
    string mainDocumentTitle = e.Title;
};
AddHandler browser.TitleChanged, Sub(sender As Object, e As TitleChangedEventArgs)
    Dim mainDocumentTitle As String = e.Title
End Sub

状态事件

当用户将光标移到链接上时,Chromium 引擎会在状态栏中显示其 URL。 JavaScript 代码也可以使用 window.statusproperty 以编程方式更改状态栏中的文本。 DotNetBrowser API 提供了获取状态栏文本更改通知的功能。

StatusChanged 事件表示状态栏文本已更改。

下面的代码示例演示了如何使用此功能:

browser.StatusChanged += delegate(object sender, StatusChangedEventArgs e)
{
    string statusText = e.Text;
};
AddHandler browser.StatusChanged, Sub(sender As Object, e As StatusChangedEventArgs)
    Dim statusText As String = e.Text
End Sub

渲染进程终止事件

每个 IBrowser 实例都与渲染网页的独立本地进程绑定。 默认情况下,Chromium 会为用户访问的每个网站实例创建一个渲染进程。 这样可以确保不同网站的页面是独立渲染的,同一网站的不同访问也能相互隔离。 因此,站点实例中的故障(例如,渲染器崩溃)或大量资源使用不会影响浏览器的其余部分。

有时这个进程会意外终止。 要接收有关渲染进程终止的通知,您可以订阅 IBrowser.RenderProcessTerminated 事件。 RenderProcessTerminatedEventArgs.ExitCode 值可用于确定这是预期的进程终止还是失败。

当您收到有关渲染进程意外终止的通知时,您可以像 Google Chrome 一样显示一个”sad”图标,例如,通知用户此特定实例崩溃。

如果在崩溃后刷新或加载相同或其他 URL,则会恢复渲染过程和 IBrowser 实例:

browser.RenderProcessTerminated += (sender, e) =>
{
    int exitCode = e.ExitCode;
    if (exitCode != 0)
    {
        // 渲染进程意外终止。
    }
};
AddHandler browser.RenderProcessTerminated, Sub(sender, e)
    Dim exitCode As Integer = e.ExitCode
    If exitCode <> 0 Then
        ' 渲染进程意外终止。
    End If
End Sub
Go Top