背水一戰 Windows 10 (63) - 控件(WebView): 基礎知識, 加載 html, http, https, ms-appx-web:///, embedded resource, ms-appdata:///, ms-local-stream://
作者: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
[源碼下載]