Xamarin.Forms(UWP) - 如何将WebView的DOM作为HTML字符串获取?

时间:2018-04-19 12:59:05

标签: xamarin webview xamarin.forms uwp xamarin.uwp

在Xamarin.Forms(UWP)项目中,我有一个WebView控件,其Source是用HTML字符串创建的,如下所示:

var webview = new Xamarin.Forms.WebView
{
    Source = new HtmlWebViewSource
    {
        Html = "<html>....</html>"
    }
};

HTML包含在<body>内动态生成HTML的JavaScript。这在屏幕上呈现完美。这意味着WebView了解使用JavaScript创建的DOM。大。

但是现在我需要解析一些生成的HTML,但我可以看到的只是我作为Source传入的原始HTML字符串,而不是最终生成的DOM。

有没有办法将由JavaScript生成并由WebView理解的DOM转换为字符串,以便我可以解析(使用像HTML Agility Pack或AngleSharp这样的库)并提取HTML的某些部分?这可以是Xamarin.Forms或UWP(我所瞄准的平台)。

注意:在完全公开的情况下(如果有帮助,并避免指责这是XY problem),我最终试图解决打印多个WebView的问题关于UWP的页面 - 对此的研究已经得到了非常稀少的信息。我有一个适用于HTML的解决方案,它不是用JavaScript动态生成的 - 基本上我正在提取代表可打印页面的HTML部分,我将它们作为单独的页面添加到打印和打印预览中。但如前所述,我似乎无法解析动态生成的内容。

1 个答案:

答案 0 :(得分:1)

我的第一个想法是使用Xamarin.Forms中内置的Eval方法,但后来我发现这个方法不会返回任何内容,所以它只适用于app-to-webview通信。

到目前为止,最简单的实现方法是使用WebView控件的自定义版本:

public class ExtendedWebView : WebView
{
    public delegate Task<string> GetHtmlRequestedHandler();

    public event GetHtmlRequestedHandler GetHtmlRequested;


    public async Task<string> GetHtmlAsync()
    {
        var handler = GetHtmlRequested;
        if (handler != null)
        {
            return await handler.Invoke();
        }
        return null;
    }
}

现在在UWP平台项目中创建一个自定义渲染器:

[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace App.UWP
{
    public class ExtendedWebViewRenderer : WebViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement != null)
            {
                var ew = (e.OldElement as ExtendedWebView);
                ew.GetHtmlRequested -= Ew_GetHtmlRequested;
            }

            if (e.NewElement != null)
            {
                var ew = (e.NewElement as ExtendedWebView);
                ew.GetHtmlRequested += Ew_GetHtmlRequested;
            }
        }

        private async Task<string> Ew_GetHtmlRequested()
        {
            return await Control.InvokeScriptAsync("eval", new string[] { "document.documentElement.outerHTML;" });
        }
    }
}

诀窍是我们正在调用JavaScript eval函数,该函数将从Web视图返回HTML本身。

您只需要使用我们的WebView替换XAML中的ExtendedWebView,并在需要时调用其GetHtmlAsync方法。

我唯一不喜欢这个解决方案的是eventTask<string>返回类型,这很奇怪。实际上已经有事件的返回类型是不寻常的。更好的解决方案是将属性放在自定义EventArgs中,本机控件将根据操作结果设置该属性,但因为InvokeScriptAsync方法是异步的(而非异步InvokeScript方法已经过时,不应再使用了)我们必须实现一个自定义Task,它将在设置属性时完成。这种方法在UWP中用于一些事件,他们正在使用&#34;推迟&#34;这表示调用者只有在一些异步操作完成后事件才会完成。我将尝试寻找一些关于如何在自定义视图的情况下调用本机异步操作的权威答案:-)。