Xamarin.Forms (UWP):如何获取WebView的DOM作为HTML字符串?
在Xamarin.Forms (UWP)中获取WebView动态生成的DOM HTML字符串
我正好处理过类似的场景,Xamarin.Forms的WebView本身并没有直接提供获取动态生成DOM的API,不过因为UWP平台的WebView是原生控件,我们可以借助它的JavaScript执行能力来实现这个需求。核心思路是通过执行JS代码获取当前页面完整的DOM结构,包括动态生成的部分,下面是具体的实现步骤:
步骤1:在共享项目中定义依赖服务接口
我们用依赖服务来实现跨平台的调用(虽然这里只针对UWP,但保持架构的一致性更好),在共享项目里创建一个接口:
public interface IWebViewDomService { // 传入Forms的WebView实例,返回当前DOM的HTML字符串 Task<string> GetCurrentHtmlAsync(Xamarin.Forms.WebView webView); }
步骤2:在UWP项目中实现该接口
在UWP项目里编写接口的实现类,利用原生WebView的InvokeScriptAsync方法执行JS获取完整HTML:
[assembly: Dependency(typeof(UwpWebViewDomService))] namespace YourAppNamespace.UWP { public class UwpWebViewDomService : IWebViewDomService { public async Task<string> GetCurrentHtmlAsync(Xamarin.Forms.WebView webView) { // 获取UWP原生的WebView控件实例 var nativeWebView = webView.GetRenderer().NativeView as Windows.UI.Xaml.Controls.WebView; if (nativeWebView == null) return string.Empty; // 执行JS获取整个文档的HTML,包括动态生成的DOM var fullHtml = await nativeWebView.InvokeScriptAsync("eval", new[] { "document.documentElement.outerHTML;" }); return fullHtml; } } }
步骤3:在共享项目中调用服务获取HTML
要确保WebView已经完成页面加载和JS执行,所以最好在Navigated事件触发后调用服务:
// 假设你的WebView实例是webview webview.Navigated += async (sender, e) => { var domService = DependencyService.Get<IWebViewDomService>(); if (domService != null) { string currentDomHtml = await domService.GetCurrentHtmlAsync(webview); // 这里就可以处理拿到的HTML字符串,比如解析你需要的部分 Console.WriteLine(currentDomHtml); } };
处理异步生成DOM的场景
如果你的页面是通过异步JS(比如AJAX请求后)动态生成DOM的,Navigated事件触发时可能DOM还没生成完成。这种情况下可以让JS在DOM准备好后通知UWP端:
- 在你的HTML的JS代码里添加通知逻辑:
// 假设在DOM动态生成完成的时机调用这个方法 function onDomReady() { // 通知UWP端DOM已准备完毕 window.external.notify('domReady'); }
- 在UWP的服务实现里监听
ScriptNotify事件,收到通知后再获取HTML:
修改UWP的服务实现,添加事件监听:
public class UwpWebViewDomService : IWebViewDomService { public async Task<string> GetCurrentHtmlAsync(Xamarin.Forms.WebView webView) { var nativeWebView = webView.GetRenderer().NativeView as Windows.UI.Xaml.Controls.WebView; if (nativeWebView == null) return string.Empty; // 监听JS的通知,处理异步DOM生成场景 nativeWebView.ScriptNotify += async (s, args) => { if (args.Value == "domReady") { var fullHtml = await nativeWebView.InvokeScriptAsync("eval", new[] { "document.documentElement.outerHTML;" }); // 通过MessagingCenter把HTML传递回共享项目 MessagingCenter.Send<object, string>(this, "WebViewDomReady", fullHtml); } }; // 如果是同步渲染的DOM,直接返回 return await nativeWebView.InvokeScriptAsync("eval", new[] { "document.documentElement.outerHTML;" }); } }
- 在共享项目中订阅MessagingCenter接收HTML:
// 在页面的构造函数或者初始化方法里订阅 MessagingCenter.Subscribe<object, string>(this, "WebViewDomReady", (sender, html) => { // 处理异步生成后的DOM HTML Console.WriteLine(html); });
注意事项
- 确保WebView已经完成渲染:
GetRenderer()只有在WebView被渲染到页面后才会返回有效实例,所以不要在页面初始化时直接调用,要在Navigated或者页面加载完成后调用。 - UWP权限配置:如果使用
window.external.notify,需要在UWP项目的Package.appxmanifest里设置允许脚本通知,或者在WebView的AllowedScriptNotifyUris属性中添加对应的URI(本地HTML可以设置为ms-appx-web:///)。
内容的提问来源于stack exchange,提问作者jbyrd
相关产品推荐
相关产品推荐

