如何从 CefSharp 3 中在本地浏览器中打开链接

8
我需要在CefSharp 3中从本地浏览器打开链接。我需要在CefSharp 3的Chromium浏览器中运行整个应用程序,除了一个表单。当我点击表单的链接按钮(例如-注册按钮。它有一个指向注册表单的链接),我需要在本地浏览器(例如-Internet Explorer)中打开此链接。
我们能否在CefSharp中实现这一点?
我在谷歌和Stack Overflow上搜索了一下,但没有找到解决方案。
5个回答

12
根据holroy的建议,我在CefSharp.Example包中的RequestHandler类中实现了OnBeforeNavigation()方法。

以下是可工作的代码:

 bool IRequestHandler.OnBeforeBrowse(IWebBrowser browserControl,
 IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
         {
             // If the url is Google open Default browser
             if (request.Url.Equals("http://google.com/"))
             {
                 // Open Google in Default browser 
                 System.Diagnostics.Process.Start("http://google.com/");
                 return true;
             }else
             {
                 // Url except Google open in CefSharp's Chromium browser
                 return false;
             }
         }

我希望这会对未来的某个人有所帮助。

谢谢,


注意:函数签名已更改。现在在 bool isRedirect 之前有一个 bool userGesture - Davis

5

首先,你需要创建一个自定义的BrowserRequestHandler类,例如:

public class BrowserRequestHandler : IRequestHandler
{
    public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
    {
        // Open in Default browser
        if (!request.Url.StartsWith("file:"))
        {
            System.Diagnostics.Process.Start(request.Url);
            return true;
        }
        return false;
    }

    public bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl,
        WindowOpenDisposition targetDisposition, bool userGesture)
    {
        return false;
    }

    public bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl,
        ISslInfo sslInfo, IRequestCallback callback)
    {
        callback.Dispose();
        return false;
    }

    public void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath)
    {
        throw new Exception("Plugin crashed!");
    }

    public CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
        IRequestCallback callback)
    {
        return CefReturnValue.Continue;
    }

    public bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port,
        string realm, string scheme, IAuthCallback callback)
    {
        callback.Dispose();
        return false;
    }

    public bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port,
        X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
    {
        callback.Dispose();
        return false;
    }

    public void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status)
    {
        throw new Exception("Browser render process is terminated!");
    }

    public bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize,
        IRequestCallback callback)
    {
        callback.Dispose();
        return false;
    }

    public void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response,
        ref string newUrl)
    {
        var url = newUrl;
        newUrl = url;
    }

    public bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url)
    {
        return url.StartsWith("mailto");
    }

    public void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser)
    {

    }

    public bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        return false;
    }

    public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
        IResponse response)
    {
        return null;
    }

    public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
        IResponse response, UrlRequestStatus status, long receivedContentLength)
    {

    }
}

这段代码中重要的部分是:

public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
{
    // Open in Default browser
    if (!request.Url.StartsWith("file:"))
    {
        System.Diagnostics.Process.Start(request.Url);
        return true;
    }
    return false;
}

在我的情况下,我正在CEF中打开本地保存的HTML文件,如果这些本地保存的HTML文件有外部链接,它们将在默认浏览器中打开。
现在你已经创建了自定义的BrowserRequestHandler,你需要将其分配给浏览器。
如果你使用MVVM,你可以在你的模型中创建一个BrowserRequestHandler并将其分配给浏览器控件的RequestHandler依赖属性。但在我的情况下,由于我有几个浏览器实例在动态打开选项卡中,并且浏览器没有足够快地打开而抛出错误,所以存在时间问题。
因此,第二个选项是使用交互命名空间设置一个Loaded事件,如下所示:
<wpf:ChromiumWebBrowser Address="{Binding Html, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="ChromiumWebBrowser">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding BrowserLoadedCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</wpf:ChromiumWebBrowser>

在此之后,您可以将浏览器添加到您的视图模型中(或在管理类中完成此操作),并像以下代码一样将其RequestHandler设置为您自定义的BrowserRequestHandler

browser.RequestHandler = new BrowserRequestHandler();

2
你可以通过从DefaultRequestHandler派生BrowserRequestHandler来跳过编写除OnBeforeBrowse(){...}方法以外的所有内容。这将提供所有样板文件。 - d ei

3
似乎可以通过使用OnBeforeNavigation或OnBeforeBrowse事件来实现。请参考来自“CEF Forum”的以下引用: OnBeforeNavigation方法的一个建议实现(摘自从Chromium Embeded(Javascript)发送信息到包含的C ++应用程序):
    //declare (i.e. in header) 
    virtual bool OnBeforeNavigation(CefRefPtr<CefBrowser> browser, 
        CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, 
        NavigationType navigation_type, bool is_redirect)  OVERRIDE; 

    //implementation 
    bool CClientApp::OnBeforeNavigation(CefRefPtr<CefBrowser> browser, 
        CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, 
        NavigationType navigation_type, bool is_redirect)
    {
        CefString cefval = request->GetURL(); 
        CString csval = cefval.c_str(); 

        if ( /* Match csval against your url/link */ )
        {
            //process the command here 

            //this is a command and not really intended for navigation 
            return true; 
        }

        return false; //true cancels navigation, false allows it 
    }

免责声明:我自己没有尝试过这段代码,但它应该可以解决问题


由于 OnBeforeNavigation 在渲染进程中执行,因此它不会被 CefSharp 暴露出来,而是使用单独的可执行文件处理子进程。然而,OnBeforeBrowse 的实现细节基本相同。https://github.com/cefsharp/CefSharp/blob/cefsharp/41/CefSharp/IRequestHandler.cs#L20 - amaitland

2

我尝试按照建议使用RequestHandler,但是我发现虽然链接在浏览器中正确打开,但ChromiumWebBrowser仍在打开空的Chromium窗口。相反,我发现可以使用ILifeSpanHandler更顺畅地实现这个过程-它允许我在弹出窗口打开时捕获并重定向该过程。

以下是我用于ILifeSpanHandler的代码:

public class ChromiumLifeSpanHandler : ILifeSpanHandler
    {
        public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
        {
            return false;
        }

        public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser)
        {

        }

        public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
        {

        }

        public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
        {
            newBrowser = null;
            System.Diagnostics.Process.Start(targetUrl);
            return true;
        }
    }

以下是我在WPF中实现它的方式(我只是将其放在网格中以便有一个地方显示静态资源):

<Grid>
    <Grid.Resources>
        <local:ChromiumLifeSpanHandler x:Key="popupHandler"/>
    </Grid.Resources>
    <cef:ChromiumWebBrowser Address="{Binding TwitterFeedAddress}" 
                            LifeSpanHandler="{StaticResource popupHandler}"/>
</Grid>

简单而美丽,谢谢! - Egil Sandfeld

0

在 Chaya 的答案中纠正一个小错别字(这个方法对我也有效)。x:Key="" 中缺少了 L。

<Grid>
    <Grid.Resources>
        <local:ChromiumLifeSpanHandler x:Key="popupHandler"/>
    </Grid.Resources>
    <cef:ChromiumWebBrowser Address="{Binding TwitterFeedAddress}" 
                            LifeSpanHandler="{StaticResource popupHandler}"/>
</Grid>

我已经修正了拼写错误。你可以提出编辑建议,而不是发布一个带有更正的答案,请参见https://stackoverflow.com/help/editing。 - amaitland

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