Skip to content

FBro浏览器关闭操作

概述

FBro提供了CloseBrowser方法来安全地关闭浏览器实例。该方法支持强制关闭和优雅关闭两种模式,并可选择是否立即将浏览器对象设置为空,以便更好地进行内存管理和对象生命周期控制。

方法签名

csharp
/// <summary>
/// 关闭浏览器
/// Request that the browser close. The JavaScript 'onbeforeunload' event will be
/// fired. If |force_close| is false the event handler, if any, will be allowed to
/// prompt the user and the user can optionally cancel the close. If |force_close|
/// is true the prompt will not be displayed and the close will proceed. Results
/// in a call to CefLifeSpanHandler::DoClose() if the event handler allows the close
/// or if |force_close| is true.
/// </summary>
/// <param name="force_close">是否强制关闭浏览器,默认为false</param>
/// <param name="set_null">是否立即设置为空,默认为false</param>
void CloseBrowser(bool force_close = false, bool set_null = false);

参数详解

force_close 参数

行为适用场景
false (默认)触发onbeforeunload事件,允许用户确认或取消关闭用户主动关闭、需要保存数据的场景
true强制关闭,不显示确认提示,直接执行关闭流程程序退出、强制清理、异常处理

set_null 参数

行为适用场景
false (默认)等待浏览器关闭事件完成后再清理对象引用普通关闭流程,需要处理关闭事件
true立即将浏览器对象设置为空,便于数组管理和快速清理批量管理、立即清理、数组元素删除

基础用法

1. 优雅关闭(推荐)

csharp
/// <summary>
/// 优雅关闭浏览器 - 允许用户确认
/// </summary>
/// <param name="browser">浏览器实例</param>
/// <returns>是否成功发起关闭请求</returns>
public bool GracefulClose(IFBroSharpBrowser browser)
{
    try
    {
        if (browser != null && browser.IsValid())
        {
            // 优雅关闭:允许触发onbeforeunload事件,用户可以取消
            browser.CloseBrowser(false, false);
            
            Console.WriteLine("浏览器关闭请求已发送,等待用户确认");
            return true;
        }
        else
        {
            Console.WriteLine("浏览器实例无效,无法关闭");
            return false;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"关闭浏览器失败: {ex.Message}");
        return false;
    }
}

2. 强制关闭

csharp
/// <summary>
/// 强制关闭浏览器 - 不允许用户取消
/// </summary>
/// <param name="browser">浏览器实例</param>
/// <returns>是否成功发起关闭请求</returns>
public bool ForceClose(IFBroSharpBrowser browser)
{
    try
    {
        if (browser != null && browser.IsValid())
        {
            // 强制关闭:不触发确认对话框,直接关闭
            browser.CloseBrowser(true, false);
            
            Console.WriteLine("浏览器强制关闭请求已发送");
            return true;
        }
        else
        {
            Console.WriteLine("浏览器实例无效,无法强制关闭");
            return false;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"强制关闭浏览器失败: {ex.Message}");
        return false;
    }
}

3. 立即清理模式

csharp
/// <summary>
/// 立即清理关闭 - 适用于批量管理
/// </summary>
/// <param name="browser">浏览器实例</param>
/// <returns>是否成功</returns>
public bool ImmediateCleanupClose(IFBroSharpBrowser browser)
{
    try
    {
        if (browser != null && browser.IsValid())
        {
            // 立即清理:强制关闭并立即设置为空
            browser.CloseBrowser(true, true);
            
            Console.WriteLine("浏览器已强制关闭并立即清理");
            return true;
        }
        else
        {
            Console.WriteLine("浏览器实例无效");
            return false;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"立即清理关闭失败: {ex.Message}");
        return false;
    }
}

高级用法

浏览器管理器示例

csharp
/// <summary>
/// 浏览器管理器 - 演示不同关闭策略
/// </summary>
public class BrowserManager
{
    private readonly List<IFBroSharpBrowser> _browsers = new List<IFBroSharpBrowser>();
    private readonly Dictionary<IFBroSharpBrowser, DateTime> _creationTimes = new Dictionary<IFBroSharpBrowser, DateTime>();

    /// <summary>
    /// 添加浏览器到管理列表
    /// </summary>
    public void AddBrowser(IFBroSharpBrowser browser)
    {
        if (browser != null && browser.IsValid())
        {
            _browsers.Add(browser);
            _creationTimes[browser] = DateTime.Now;
            Console.WriteLine($"浏览器已添加到管理列表,当前总数: {_browsers.Count}");
        }
    }

    /// <summary>
    /// 优雅关闭指定浏览器
    /// </summary>
    public bool CloseSpecificBrowser(IFBroSharpBrowser browser, bool waitForConfirmation = true)
    {
        try
        {
            if (!_browsers.Contains(browser))
            {
                Console.WriteLine("指定的浏览器不在管理列表中");
                return false;
            }

            if (waitForConfirmation)
            {
                // 优雅关闭,等待用户确认
                browser.CloseBrowser(false, false);
                Console.WriteLine("已发送关闭请求,等待用户确认");
            }
            else
            {
                // 强制关闭
                browser.CloseBrowser(true, false);
                Console.WriteLine("浏览器已强制关闭");
                
                // 从管理列表中移除
                RemoveBrowserFromList(browser);
            }

            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"关闭指定浏览器失败: {ex.Message}");
            return false;
        }
    }

    /// <summary>
    /// 批量关闭所有浏览器
    /// </summary>
    public int CloseAllBrowsers(bool forceClose = false, bool immediateCleanup = false)
    {
        int closedCount = 0;
        var browsersToClose = new List<IFBroSharpBrowser>(_browsers);

        foreach (var browser in browsersToClose)
        {
            try
            {
                if (browser != null && browser.IsValid())
                {
                    browser.CloseBrowser(forceClose, immediateCleanup);
                    closedCount++;

                    if (immediateCleanup)
                    {
                        // 立即从列表中移除
                        RemoveBrowserFromList(browser);
                    }

                    Console.WriteLine($"浏览器关闭请求已发送 ({closedCount}/{browsersToClose.Count})");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"批量关闭浏览器失败: {ex.Message}");
            }
        }

        Console.WriteLine($"批量关闭完成,成功关闭 {closedCount} 个浏览器");
        return closedCount;
    }

    /// <summary>
    /// 关闭运行时间超过指定时长的浏览器
    /// </summary>
    public int CloseOldBrowsers(TimeSpan maxAge, bool forceClose = true)
    {
        int closedCount = 0;
        var cutoffTime = DateTime.Now - maxAge;
        var oldBrowsers = new List<IFBroSharpBrowser>();

        // 找出需要关闭的旧浏览器
        foreach (var kvp in _creationTimes)
        {
            if (kvp.Value < cutoffTime && _browsers.Contains(kvp.Key))
            {
                oldBrowsers.Add(kvp.Key);
            }
        }

        // 关闭旧浏览器
        foreach (var browser in oldBrowsers)
        {
            try
            {
                if (browser != null && browser.IsValid())
                {
                    browser.CloseBrowser(forceClose, true); // 立即清理
                    RemoveBrowserFromList(browser);
                    closedCount++;

                    Console.WriteLine($"已关闭运行时间超过 {maxAge.TotalMinutes:F1} 分钟的浏览器");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"关闭旧浏览器失败: {ex.Message}");
            }
        }

        Console.WriteLine($"旧浏览器清理完成,关闭了 {closedCount} 个浏览器");
        return closedCount;
    }

    /// <summary>
    /// 应急关闭所有浏览器
    /// </summary>
    public void EmergencyShutdown()
    {
        Console.WriteLine("执行应急关闭程序...");
        
        try
        {
            // 强制关闭所有浏览器,立即清理
            CloseAllBrowsers(true, true);
            
            // 清空管理列表
            _browsers.Clear();
            _creationTimes.Clear();
            
            Console.WriteLine("应急关闭完成");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"应急关闭失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 从管理列表中移除浏览器
    /// </summary>
    private void RemoveBrowserFromList(IFBroSharpBrowser browser)
    {
        _browsers.Remove(browser);
        _creationTimes.Remove(browser);
    }

    /// <summary>
    /// 获取管理器状态
    /// </summary>
    public BrowserManagerStatus GetStatus()
    {
        var validBrowsers = _browsers.Count(b => b != null && b.IsValid());
        
        return new BrowserManagerStatus
        {
            TotalBrowsers = _browsers.Count,
            ValidBrowsers = validBrowsers,
            InvalidBrowsers = _browsers.Count - validBrowsers,
            OldestBrowserAge = _creationTimes.Count > 0 ? DateTime.Now - _creationTimes.Values.Min() : (TimeSpan?)null,
            NewestBrowserAge = _creationTimes.Count > 0 ? DateTime.Now - _creationTimes.Values.Max() : (TimeSpan?)null
        };
    }
}

/// <summary>
/// 浏览器管理器状态信息
/// </summary>
public class BrowserManagerStatus
{
    public int TotalBrowsers { get; set; }
    public int ValidBrowsers { get; set; }
    public int InvalidBrowsers { get; set; }
    public TimeSpan? OldestBrowserAge { get; set; }
    public TimeSpan? NewestBrowserAge { get; set; }

    public override string ToString()
    {
        return $"总数: {TotalBrowsers}, 有效: {ValidBrowsers}, 无效: {InvalidBrowsers}";
    }
}

浏览器关闭事件处理

生命周期事件处理

csharp
/// <summary>
/// 浏览器生命周期事件处理器
/// </summary>
public class BrowserLifeSpanHandler : FBroSharpLifeSpanHandler
{
    private readonly Action<IFBroSharpBrowser> _onBrowserClosed;

    public BrowserLifeSpanHandler(Action<IFBroSharpBrowser> onBrowserClosed = null)
    {
        _onBrowserClosed = onBrowserClosed;
    }

    /// <summary>
    /// 浏览器即将关闭事件
    /// </summary>
    public override bool DoClose(IFBroSharpBrowser browser)
    {
        try
        {
            Console.WriteLine("浏览器即将关闭,执行清理操作");
            
            // 这里可以执行关闭前的清理工作
            // 返回 false 允许关闭继续进行
            // 返回 true 会阻止关闭(不推荐)
            
            return false; // 允许关闭
        }
        catch (Exception ex)
        {
            Console.WriteLine($"DoClose事件处理失败: {ex.Message}");
            return false; // 即使出错也允许关闭
        }
    }

    /// <summary>
    /// 浏览器已关闭事件
    /// </summary>
    public override void OnBeforeClose(IFBroSharpBrowser browser)
    {
        try
        {
            Console.WriteLine("浏览器已关闭,执行最终清理");
            
            // 执行最终的清理工作
            _onBrowserClosed?.Invoke(browser);
            
            // 注意:根据FBro事件类传递机制,这里的browser参数只在方法作用域内有效
            // 如果需要保存browser引用,应该在其他地方使用强拷贝
        }
        catch (Exception ex)
        {
            Console.WriteLine($"OnBeforeClose事件处理失败: {ex.Message}");
        }
    }
}

关闭确认处理

csharp
/// <summary>
/// 关闭确认处理器
/// </summary>
public class BrowserCloseConfirmationHandler
{
    /// <summary>
    /// 处理关闭确认对话框
    /// </summary>
    public static bool HandleCloseConfirmation(IFBroSharpBrowser browser, string message = null)
    {
        try
        {
            // 注入JavaScript来处理onbeforeunload事件
            string script = $@"
                window.addEventListener('beforeunload', function(e) {{
                    var confirmationMessage = '{message ?? "确定要关闭浏览器吗?"}';
                    e.returnValue = confirmationMessage;
                    return confirmationMessage;
                }});
            ";

            var frame = browser.GetMainFrame();
            if (frame != null && frame.IsValid())
            {
                frame.ExecuteJavaScript(script, "", 0);
                Console.WriteLine("关闭确认处理器已设置");
                return true;
            }
            else
            {
                Console.WriteLine("无法设置关闭确认处理器:主框架无效");
                return false;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"设置关闭确认处理器失败: {ex.Message}");
            return false;
        }
    }

    /// <summary>
    /// 移除关闭确认
    /// </summary>
    public static bool RemoveCloseConfirmation(IFBroSharpBrowser browser)
    {
        try
        {
            string script = @"
                window.onbeforeunload = null;
                window.removeEventListener('beforeunload', arguments.callee);
            ";

            var frame = browser.GetMainFrame();
            if (frame != null && frame.IsValid())
            {
                frame.ExecuteJavaScript(script, "", 0);
                Console.WriteLine("关闭确认已移除");
                return true;
            }
            else
            {
                Console.WriteLine("无法移除关闭确认:主框架无效");
                return false;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"移除关闭确认失败: {ex.Message}");
            return false;
        }
    }
}

使用场景和最佳实践

场景1:用户主动关闭

csharp
/// <summary>
/// 用户点击关闭按钮
/// </summary>
private void OnUserCloseRequest()
{
    // 允许用户确认,保护未保存的数据
    if (browser != null && browser.IsValid())
    {
        browser.CloseBrowser(false, false);
    }
}

场景2:程序退出时清理

csharp
/// <summary>
/// 应用程序退出时的清理
/// </summary>
private void OnApplicationExit()
{
    if (browser != null && browser.IsValid())
    {
        // 强制关闭,不等待用户确认
        browser.CloseBrowser(true, true);
    }
}

场景3:批量管理场景

csharp
/// <summary>
/// 清理浏览器数组
/// </summary>
private void CleanupBrowserArray(List<IFBroSharpBrowser> browsers)
{
    for (int i = browsers.Count - 1; i >= 0; i--)
    {
        var browser = browsers[i];
        if (browser != null && browser.IsValid())
        {
            // 立即清理模式,便于数组管理
            browser.CloseBrowser(true, true);
            browsers.RemoveAt(i); // 可以立即删除数组元素
        }
    }
}

场景4:异常处理

csharp
/// <summary>
/// 异常情况下的强制清理
/// </summary>
private void HandleBrowserError(IFBroSharpBrowser browser)
{
    try
    {
        if (browser != null)
        {
            // 异常情况强制关闭
            browser.CloseBrowser(true, true);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"异常处理中的浏览器关闭失败: {ex.Message}");
        // 即使关闭失败也要继续其他清理工作
    }
}

参数组合使用指南

force_closeset_null适用场景行为描述
falsefalse用户主动关闭显示确认对话框,等待事件完成后清理
truefalse程序控制关闭立即关闭,等待事件完成后清理
falsetrue需要确认的快速清理显示确认对话框,立即设置对象为空
truetrue强制立即清理立即关闭并设置对象为空,适合批量操作

注意事项

1. 事件类传递机制

根据FBro的事件类传递机制,在事件处理器中接收到的浏览器参数只在方法作用域内有效:

csharp
public override void OnBeforeClose(IFBroSharpBrowser browser)
{
    // ❌ 错误:直接保存参数引用
    // this.savedBrowser = browser; // 会失效
    
    // ✅ 正确:如果需要保存,应该在此之前使用强拷贝
    // this.savedBrowser = new FBroSharpBrowser(browser);
    
    // 在方法内直接使用是安全的
    Console.WriteLine($"浏览器已关闭: {browser.GetIdentifier()}");
}

2. 内存管理

  • 使用set_null = true时,浏览器对象会立即被设置为空
  • 适合在数组或列表中快速移除元素
  • 可以减少等待事件完成的时间

3. 线程安全

csharp
/// <summary>
/// 线程安全的浏览器关闭
/// </summary>
private readonly object _closeLock = new object();

public bool SafeClose(IFBroSharpBrowser browser, bool force = false)
{
    lock (_closeLock)
    {
        try
        {
            if (browser != null && browser.IsValid())
            {
                browser.CloseBrowser(force, false);
                return true;
            }
            return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"线程安全关闭失败: {ex.Message}");
            return false;
        }
    }
}

4. 错误处理最佳实践

csharp
/// <summary>
/// 健壮的浏览器关闭方法
/// </summary>
public static bool RobustClose(IFBroSharpBrowser browser, bool force = false, bool immediate = false)
{
    if (browser == null)
    {
        Console.WriteLine("浏览器实例为null,无需关闭");
        return true;
    }

    try
    {
        // 检查浏览器是否仍然有效
        if (!browser.IsValid())
        {
            Console.WriteLine("浏览器实例已无效,无需关闭");
            return true;
        }

        // 执行关闭操作
        browser.CloseBrowser(force, immediate);
        
        string mode = force ? "强制" : "优雅";
        string cleanup = immediate ? "立即清理" : "延迟清理";
        Console.WriteLine($"浏览器关闭请求已发送 - {mode}关闭,{cleanup}");
        
        return true;
    }
    catch (ObjectDisposedException)
    {
        Console.WriteLine("浏览器对象已被释放");
        return true; // 对象已释放视为成功
    }
    catch (Exception ex)
    {
        Console.WriteLine($"关闭浏览器时发生错误: {ex.Message}");
        return false;
    }
}

通过这些方法和最佳实践,您可以在各种场景下安全、有效地关闭FBro浏览器实例,确保资源得到正确管理和清理。

browser.CloseBrowser(false, false);

如果文档对您有帮助,欢迎 请喝咖啡 ☕ | 软件发布 | 源码购买