作者:webabcd
介绍
背水一战 Windows 10 之 控件(WebView)
- 基础知识
- 加载指定的 html
- 加载指定的 url(http, https, ms-appx-web:///, embedded resource, ms-appdata:///)
- 结合 IUriToStreamResolver 可以实现自定义所有请求(包括 html 的 url 以及 html 内所有引用的 url)返回的内容(ms-local-stream://)
示例
1、演示 WebView 的基础知识
Controls/WebViewDemo/WebViewDemo1.xaml
<Page x:Class="Windows10.Controls.WebViewDemo.WebViewDemo1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.WebViewDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="10 0 10 10"> <Button Name="btnNavigateUrl" Content="加载指定的 url" Click="btnNavigateUrl_Click" Margin="5" /> <WebView Name="webView" Width="800" Height="400" HorizontalAlignment="Left" Margin="5" /> </StackPanel> </Grid> </Page>
Controls/WebViewDemo/WebViewDemo1.xaml.cs
/* * WebView - 内嵌浏览器控件(继承自 FrameworkElement, 请参见 /Controls/BaseControl/FrameworkElementDemo/) * * * 本例用于演示 WebView 的基础知识 */ using System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace Windows10.Controls.WebViewDemo { public sealed partial class WebViewDemo1 : Page { public WebViewDemo1() { this.InitializeComponent(); } private void btnNavigateUrl_Click(object sender, RoutedEventArgs e) { // 加载指定的 url webView.Navigate(new Uri("http://webabcd.cnblogs.com/", UriKind.Absolute)); // 获取或设置浏览器的 url // webView.Source = new Uri("http://webabcd.cnblogs.com/", UriKind.Absolute); // web 页面中的某一个 frame 加载前 webView.FrameNavigationStarting += webView_FrameNavigationStarting; // web 页面中的某一个 frame 加载中 webView.FrameContentLoading += webView_FrameContentLoading; // web 页面中的某一个 frame 的 DOM 加载完成 webView.FrameDOMContentLoaded += webView_FrameDOMContentLoaded; // web 页面中的某一个 frame 导航完成(成功或失败) webView.FrameNavigationCompleted += webView_FrameNavigationCompleted; // web 页面加载前 webView.NavigationStarting += webView_NavigationStarting; // web 页面加载中 webView.ContentLoading += webView_ContentLoading; // web 页面的 DOM 加载完成 webView.DOMContentLoaded += webView_DOMContentLoaded; // web 页面导航完成(成功或失败) webView.NavigationCompleted += webView_NavigationCompleted; // 当脚本运行时,可能会导致 app 无响应。此事件会定期执行,然后可查看 ExecutionTime 属性,如果要暂停脚本,则将 StopPageScriptExecution 属性设置为 true 即可 webView.LongRunningScriptDetected += webView_LongRunningScriptDetected; // 在 WebView 对 SmartScreen 筛选器报告为不安全的内容显示警告页面时发生 webView.UnsafeContentWarningDisplaying += webView_UnsafeContentWarningDisplaying; // 在 WebView 尝试下载不受支持的文件时发生 webView.UnviewableContentIdentified += webView_UnviewableContentIdentified; // 用于导航 web 的一系列 api,顾名思义,不解释了 // webView.CanGoBack; // webView.GoBack(); // webView.CanGoForward; // webView.GoForward(); // webView.Stop(); // webView.Refresh(); // 设置焦点 // webView.Focus(FocusState.Programmatic); // 清除 WebView 的缓存和 IndexedDB 数据 // await WebView.ClearTemporaryWebDataAsync(); // WebView 在实例化时可以指定其是托管在 UI 线程(WebViewExecutionMode.SameThread)还是托管在非 UI 线程(WebViewExecutionMode.SeparateThread),默认是托管在 UI 线程的 // WebView wv = new WebView(WebViewExecutionMode.SeparateThread); // 获知 WebView 是托管在 UI 线程还是非 UI 线程 // WebViewExecutionMode executionMode = webView.ExecutionMode; } void webView_FrameNavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args) { // 是否取消此 url 的加载 // args.Cancel = true; // args.Uri } void webView_FrameContentLoading(WebView sender, WebViewContentLoadingEventArgs args) { // args.Uri } void webView_FrameDOMContentLoaded(WebView sender, WebViewDOMContentLoadedEventArgs args) { // args.Uri } void webView_FrameNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args) { // 导航是否成功 // args.IsSuccess // 导航失败时,失败原因的 WebErrorStatus 枚举 // args.WebErrorStatus } void webView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args) { // 是否取消此 url 的加载 // args.Cancel = true; // args.Uri } void webView_ContentLoading(WebView sender, WebViewContentLoadingEventArgs args) { // args.Uri } void webView_DOMContentLoaded(WebView sender, WebViewDOMContentLoadedEventArgs args) { // args.Uri } void webView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args) { // 导航是否成功 // args.IsSuccess // 导航失败时,失败原因的 WebErrorStatus 枚举 // args.WebErrorStatus } // 在 WebView 尝试下载不受支持的文件时发生 void webView_UnviewableContentIdentified(WebView sender, WebViewUnviewableContentIdentifiedEventArgs args) { // 引用页 // args.Referrer // args.Uri } // 在 WebView 对 SmartScreen 筛选器报告为不安全的内容显示警告页面时发生 void webView_UnsafeContentWarningDisplaying(WebView sender, object args) { } // 当脚本运行时,可能会导致 app 无响应。此事件会定期执行,然后可查看 ExecutionTime 属性,如果要暂停脚本,则将 StopPageScriptExecution 属性设置为 true 即可 void webView_LongRunningScriptDetected(WebView sender, WebViewLongRunningScriptDetectedEventArgs args) { // 获取 WebView 执行的一个长时间运行的脚本的运行时间(单位:毫秒) // args.ExecutionTime // 是否暂停在 WebView 中执行的已运行很长时间的脚本 // args.StopPageScriptExecution } } }
2、演示 WebView 如何加载 html, http, https, ms-appx-web:///, embedded resource, ms-appdata:///, ms-local-stream://
Controls/WebViewDemo/demo1.html
<b>i am demo1.html</b>
Controls/WebViewDemo/demo2.html
<b>i am demo2.html</b>
Controls/WebViewDemo/demo3.html
<b>i am demo3.html</b>
Controls/WebViewDemo/demo4.html
<!DOCTYPE html> <html> <head> <link href="css.css" rel="stylesheet" /> </head> <body> <b>i am demo4.html</b> </body> </html>
Controls/WebViewDemo/WebViewDemo2.xaml
<Page x:Class="Windows10.Controls.WebViewDemo.WebViewDemo2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.WebViewDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="10 0 10 10"> <Button Name="btnNavigate" Content="通过 Navigate 加载指定的 url" Click="btnNavigate_Click" Margin="5" /> <Button Name="btnSource" Content="通过 Source 获取或设置当前的 url" Click="btnSource_Click" Margin="5" /> <Button Name="btnNavigateToString" Content="通过 NavigateToString 加载指定的 html" Click="btnNavigateToString_Click" Margin="5" /> <Button Name="btnMsAppxWeb" Content="加载指定的 ms-appx-web:/// 协议地址(Package 内的数据)" Click="btnMsAppxWeb_Click" Margin="5" /> <Button Name="btnEmbeddedResource" Content="加载指定的嵌入式资源(Package 内的数据)" Click="btnEmbeddedResource_Click" Margin="5" /> <Button Name="btnMsAppdata" Content="加载指定的 ms-appdata:/// 协议地址(Application 内的数据)" Click="btnMsAppdata_Click" Margin="5" /> <Button Name="btnMsLocalStream" Content="加载指定的 ms-local-stream:// 协议地址" Click="btnMsLocalStream_Click" Margin="5" /> <WebView Name="webView" Width="800" Height="400" HorizontalAlignment="Left" Margin="5" /> </StackPanel> </Grid> </Page>
Controls/WebViewDemo/WebViewDemo2.xaml.cs
/* * WebView - 内嵌浏览器控件(继承自 FrameworkElement, 请参见 /Controls/BaseControl/FrameworkElementDemo/) * * * 本例用于演示 * 1、WebView 如何加载指定的 html * 2、WebView 如何加载指定的 url(http, https, ms-appx-web:///, embedded resource, ms-appdata:///) * 3、WebView 结合 IUriToStreamResolver 可以实现自定义所有请求(包括 html 的 url 以及 html 内所有引用的 url)返回的内容(ms-local-stream://) */ using System; using System.IO; using System.Reflection; using System.Threading.Tasks; using Windows.Foundation; using Windows.Security.Cryptography; using Windows.Storage; using Windows.Storage.Streams; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.Web; namespace Windows10.Controls.WebViewDemo { public sealed partial class WebViewDemo2 : Page { public WebViewDemo2() { this.InitializeComponent(); } private void btnNavigate_Click(object sender, RoutedEventArgs e) { // 通过 Navigate 加载指定的 url webView.Navigate(new Uri("http://webabcd.cnblogs.com/", UriKind.Absolute)); } private void btnSource_Click(object sender, RoutedEventArgs e) { // 通过 Source 获取或设置当前的 url webView.Source = new Uri("https://www.baidu.com", UriKind.Absolute); } private void btnNavigateToString_Click(object sender, RoutedEventArgs e) { // 通过 NavigateToString 加载指定的 html webView.NavigateToString("<b>i am webabcd</b>"); } private void btnMsAppxWeb_Click(object sender, RoutedEventArgs e) { // 加载指定的 ms-appx-web:/// 协议地址(Package 内的数据) webView.Navigate(new Uri("ms-appx-web:///Controls/WebViewDemo/demo1.html", UriKind.Absolute)); } private void btnEmbeddedResource_Click(object sender, RoutedEventArgs e) { // 获取 Package 内嵌入式资源数据 Assembly assembly = typeof(WebViewDemo2).GetTypeInfo().Assembly; Stream stream = assembly.GetManifestResourceStream("Windows10.Controls.WebViewDemo.demo2.html"); using (StreamReader reader = new StreamReader(stream)) { string html = reader.ReadToEnd(); webView.NavigateToString(html); } } private async void btnMsAppdata_Click(object sender, RoutedEventArgs e) { // 将程序包内的 html 文件复制到 ApplicationData 中的 LocalFolder StorageFolder localFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("webabcdTest", CreationCollisionOption.OpenIfExists); StorageFile htmlFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Controls/WebViewDemo/demo3.html")); await htmlFile.CopyAsync(localFolder, "demo3.html", NameCollisionOption.ReplaceExisting); // 加载指定的 ms-appdata:/// 协议地址(Application 内的数据) string url = "ms-appdata:///local/webabcdTest/demo3.html"; webView.Navigate(new Uri(url)); } private void btnMsLocalStream_Click(object sender, RoutedEventArgs e) { // 构造可传递给 NavigateToLocalStreamUri() 的 URI(即 ms-local-stream:// 协议的 URI) Uri url = webView.BuildLocalStreamUri("contentIdentifier", "/Controls/WebViewDemo/demo4.html"); // 在我的示例中,上面方法返回的 url 如下(协议是: ms-local-stream://appname_KEY/folder/file, 其中的 KEY 会根据 contentIdentifier 的不同而不同) // "ms-local-stream://48c7dd54-1ef2-4db7-a75e-7e02c5eefd40_636f6e74656e744964656e746966696572/Controls/WebViewDemo/demo4.html" // 实例化一个实现 IUriToStreamResolver 接口的类 StreamUriWinRTResolver myResolver = new StreamUriWinRTResolver(); // 所有 url(包括 html 的 url 以及 html 内所有引用的 url)都会通过 StreamUriWinRTResolver 来返回数据流 webView.NavigateToLocalStreamUri(url, myResolver); } } // 实现 IUriToStreamResolver 接口(用于响应所有 url 请求,包括 html 的 url 以及 html 内所有引用的 url) // 可以认为这就是一个为 WebView 服务的 http server public sealed class StreamUriWinRTResolver : IUriToStreamResolver { // IUriToStreamResolver 接口只有一个需要实现的方法 // 根据当前请求的 uri 返回对应的内容流 public IAsyncOperation<IInputStream> UriToStreamAsync(Uri uri) { return GetContent(uri).AsAsyncOperation(); } // 根据当前请求的 uri 返回对应的内容流 private async Task<IInputStream> GetContent(Uri uri) { string path = uri.AbsolutePath; string responseString = ""; switch (path) { case "/Controls/WebViewDemo/demo4.html": StorageFile fileRead = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx://" + path, UriKind.Absolute)); return await fileRead.OpenAsync(FileAccessMode.Read); case "/Controls/WebViewDemo/css.css": responseString = "b { color: red; }"; break; default: break; } // string 转 IInputStream IBuffer buffer = CryptographicBuffer.ConvertStringToBinary(responseString, BinaryStringEncoding.Utf8); var stream = new InMemoryRandomAccessStream(); await stream.WriteAsync(buffer); return stream.GetInputStreamAt(0); } } }
OK
[源码下载]