背水一戰 Windows 10 (64) - 控件(WebView): 加載指定 HttpMethod 的請求, 自定義請求的 http header, app 與 js 的交互


[源碼下載]


背水一戰 Windows 10 (64) - 控件(WebView): 加載指定 HttpMethod 的請求, 自定義請求的 http header, app 與 js 的交互



作者:webabcd


介紹
背水一戰 Windows 10 之 控件(WebView)

  • 加載指定 HttpMethod 的請求
  • 自定義請求的 http header
  • app 與 js 的交互



示例
1、演示 WebView 如何加載指定 HttpMethod 的請求以及如何自定義請求的 http header
WebApi/Controllers/WebViewPostController.cs

/*
 * 用於 WebView 演示“如何加載指定 HttpMethod 的請求,以及如何自定義請求的 http header”
 */

using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;

namespace WebApi.Controllers
{
    public class WebViewPostController : ApiController
    {
        [HttpPost]
        public async Task<HttpResponseMessage> Post()
        {
            Stream stream = await this.Request.Content.ReadAsStreamAsync();
            StreamReader sr = new StreamReader(stream);
            string postData = sr.ReadToEnd();
            sr.Dispose();

            string myHeader = this.Request.Headers.GetValues("myHeader").FirstOrDefault();

            HttpResponseMessage result = new HttpResponseMessage
            {
                Content = new StringContent($"post data: {postData}<br /> myHeader: {myHeader}", Encoding.UTF8, "text/html")
            };

            return result;
        }
    }
}

Controls/WebViewDemo/WebViewDemo3.xaml

<Page
    x:Class="Windows10.Controls.WebViewDemo.WebViewDemo3"
    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 0 0">

            <WebView Name="webView" Width="800" Height="300" HorizontalAlignment="Left" />

        </StackPanel>
    </Grid>
</Page>

Controls/WebViewDemo/WebViewDemo3.xaml.cs

/*
 * WebView - 內嵌瀏覽器控件(繼承自 FrameworkElement, 請參見 /Controls/BaseControl/FrameworkElementDemo/)
 *     
 *     
 * 本例用於演示 
 * 1、WebView 如何加載指定 HttpMethod 的請求
 * 2、WebView 如何自定義請求的 http header
 */
 
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Web.Http;

namespace Windows10.Controls.WebViewDemo
{
    public sealed partial class WebViewDemo3 : Page
    {
        public WebViewDemo3()
        {
            this.InitializeComponent();

            this.Loaded += WebViewDemo3_Loaded;
        }

        private void WebViewDemo3_Loaded(object sender, RoutedEventArgs e)
        {
            // 實例化 HttpRequestMessage(可以指定請求的 HttpMethod 以及自定義請求的 http header)
            HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri("http://localhost:44914/api/webviewpost"));

            // 構造 post 數據
            httpRequestMessage.Content = new HttpStringContent("hello webabcd");

            // 自定義 http header
            httpRequestMessage.Headers.Append("myHeader", "hello header");

            // 通過 NavigateWithHttpRequestMessage 加載指定的 HttpRequestMessage 對象
            webView.NavigateWithHttpRequestMessage(httpRequestMessage);
        }
    }
}


2、演示 app 與 js 的交互
MyRuntimeComponent/JS2WRC.cs

/*
 * 用於演示 javascript 調用 windows runtime component 中定義的方法
 */

using Windows.Foundation.Metadata;

namespace MyRuntimeComponent
{
    [AllowForWeb] // 允許 js 調用
    public sealed class JS2WRC // 注意:在 winrc 中用 c# 寫的類必須是 sealed 的
    {
        public string hello(string name)
        {
            return $"hello: {name}";
        }
    }
}

Controls/WebViewDemo/WebViewJavaScript.html

<!--此 html 用於演示 app 與 js 間的交互-->

<!doctype html>
<html>
<head>
    <title>i am title</title>
    <script type='text/javascript'>

        // app 調用 js 函數
        function appToJs(name) {
            return 'app to js: ' + name;
        }

        // js 傳遞數據到 app
        function jsToApp() {
            window.external.notify('js to app');
        }

        // js 調用 wrc
        function jsToWRC() {
            if (window.js2wrc_object) {
                // js 調用 wrc(在 windows runtime component 中定義的方法)
                var result = js2wrc_object.hello("webabcd");
                document.getElementById("div").innerHTML = result;
            }
        }

        // 彈出 alert 框
        function showAlert() {
            // 在 uwp 的 webview 中是不能彈出 alert 框的(可以在 c# 中拐彎抹角的實現,參見本例的 c# 端的代碼)
            alert("hello: alert");
        }

    </script>
</head>
<body>
    
    <p>
        <input type='button' onclick='jsToApp();' value='js 傳遞數據到 app' />
    </p>

    <p>
        <input type='button' onclick='jsToWRC();' value='js 調用 wrc' />
    </p>

    <p>
        <div id="div"></div>
    </p>

    <p>
        <input type='button' onclick='showAlert();' value='彈出 alert 框' />
    </p>
    
</body>
</html>

Controls/WebViewDemo/WebViewDemo4.xaml

<Page
    x:Class="Windows10.Controls.WebViewDemo.WebViewDemo4"
    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">

            <TextBlock Name="lblMsg" Margin="5" />

            <Button Name="btnAppToJavaScript" Content="app 調用 WebView 加載的 html 中的 JavaScript 函數" Click="btnAppToJavaScript_Click" Margin="5" />

            <Button Name="btnEval" Content="通過 eval 訪問 DOM" Click="btnEval_Click" Margin="5" />

            <Button Name="btnRegisterJavaScript" Content="通過 eval 向 html 注冊 JavaScript 腳本" Click="btnRegisterJavaScript_Click" Margin="5" />

            <!--
                通過 ms-appx-web 加載包內的 html 頁面
            -->
            <WebView Name="webView" Width="480" Height="320" Source="ms-appx-web:///Controls/WebViewDemo/WebViewJavaScript.html" HorizontalAlignment="Left" Margin="5" 
                     NavigationStarting="WebView_NavigationStarting" NavigationCompleted="WebView_NavigationCompleted" />

        </StackPanel>
    </Grid>
</Page>

Controls/WebViewDemo/WebViewDemo4.xaml.cs

/*
 * WebView - 內嵌瀏覽器控件(繼承自 FrameworkElement, 請參見 /Controls/BaseControl/FrameworkElementDemo/)
 *     InvokeScriptAsync() - 調用指定的 js 函數,並返回 js 函數的返回值
 *     ScriptNotify - 收到 js 通過 window.external.notify('') 傳遞過來的數據時觸發的事件
 *     AllowedScriptNotifyUris - 允許觸發 ScriptNotify 事件的 uri 列表
 *     AddWebAllowedObject() - 將 windows runtime component 中定義的對象注冊到 WebView 加載的頁面(需要在 WebView 的 NavigationStarting 事件中調用)
 *
 * 
 * 本例用於演示
 * 1、app 與 js 的交互
 * 2、如何將 windows runtime component 中定義的對象注冊到 WebView 加載的頁面,以便通過 js 調用 wrc
 */

/*
 * 特別注意:各種 uri schema 對於 ScriptNotify 的支持情況如下
 * 1、http:// 不支持
 * 2、https:// 支持,需要在 appxmanifest 中設置允許的 URI(http 的不行,只能是 https 的),也可以通過 WebView 的 AllowedScriptNotifyUris 屬性來設置或獲取
 *    <ApplicationContentUriRules>
 *       <Rule Match="https://aaa.aaa.aaa" Type="include" />
 *    </ApplicationContentUriRules>
 * 3、ms-appdata:/// 不支持
 * 4、ms-appx-web:/// 支持
 * 5、ms-local-stream:// 支持
 */

using System;
using System.Collections.Generic;
using Windows.UI;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Windows10.Controls.WebViewDemo
{
    public sealed partial class WebViewDemo4 : Page
    {
        public WebViewDemo4()
        {
            this.InitializeComponent();

            webView.ScriptNotify += webView_ScriptNotify;
            webView.NavigationCompleted += webView_NavigationCompleted;

            // 由於本例的 webview 是在 xaml 中聲明並指定需要加載的 html 的,所以對於 NavigationStarting 事件的注冊來說要在 xaml 做
            // webView.NavigationStarting += WebView_NavigationStarting;
        }

        void webView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
        {
            if (args.IsSuccess)
            {
                // 獲取 html 標題
                lblMsg.Text = "html title: " + webView.DocumentTitle;
                lblMsg.Text += Environment.NewLine;

                // 獲取或設置 html 背景色
                webView.DefaultBackgroundColor = Colors.Orange;
                lblMsg.Text += "html backgroundColor: " + webView.DefaultBackgroundColor.ToString();
            }
        }

        // 收到 js 通過 window.external.notify('') 傳遞過來的數據時觸發的事件
        private async void webView_ScriptNotify(object sender, NotifyEventArgs e)
        {
            // e.Value - 獲取 js 傳遞過來的數據
            // e.CallingUri - 觸發此事件的頁面的 uri

            if (e.Value.StartsWith("alert:"))
            {
                // 模擬彈出頁面的 alert 框(參見下面的 WebView_NavigationCompleted 中的代碼)
                await new MessageDialog(e.Value.Substring(6), "alert").ShowAsync();
            }
            else
            {
                await new MessageDialog(e.CallingUri.ToString() + " " + e.Value).ShowAsync();
            }
        }

        // app 調用 js
        private async void btnAppToJavaScript_Click(object sender, RoutedEventArgs e)
        {
            List<string> arguments = new List<string> { "webabcd" };
            // 調用 js 方法:sayHelloToJs('webabcd'); 並返回結果
            string result = await webView.InvokeScriptAsync("appToJs", arguments);

            await new MessageDialog(result).ShowAsync();
        }

        // 通過 eval 訪問 DOM
        private async void btnEval_Click(object sender, RoutedEventArgs e)
        {
            // 設置 document.title 的值(用於演示如何通過 eval 設置 DOM)
            List<string> arguments = new List<string> { "document.title = 'hahaha';" };
            await webView.InvokeScriptAsync("eval", arguments);

            // 獲取 document.title 的值(用於演示如何通過 eval 獲取 DOM)
            arguments = new List<string> { "document.title;" };
            string result = await webView.InvokeScriptAsync("eval", arguments);
            await new MessageDialog(result).ShowAsync();
        }

        // 通過 eval 向 html 注冊 JavaScript 腳本
        private async void btnRegisterJavaScript_Click(object sender, RoutedEventArgs e)
        {
            // 向 html 注冊腳本
            List<string> arguments = new List<string> { "function xxx(){return '由 app 向 html 注冊的腳本返回的數據';}" };
            await webView.InvokeScriptAsync("eval", arguments);

            // 調用剛剛注冊的腳本
            string result = await webView.InvokeScriptAsync("xxx", null);

            await new MessageDialog(result).ShowAsync();
        }

        // js 調用 wrc
        private void WebView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
        {
            // 注意:需要在 WebView 的 NavigationStarting 事件中調用 AddWebAllowedObject()
            webView.AddWebAllowedObject("js2wrc_object", new MyRuntimeComponent.JS2WRC());
        }

        // 模擬彈出頁面的 alert 框
        private async void WebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
        {
            // 在 uwp 的 webview 中是不能彈出 alert 框的
            // 可以向頁面注入腳本重寫 window.alert 函數,使其調用 window.external.notify 通知 c# 端,然后彈出 MessageDialog 框以模擬頁面的 alert 框(參見上面的 webView_ScriptNotify 中的代碼)
            // 在 uwp 的 webview 中也是不能彈出 confirm 框的,也不能像實現 alert 框那樣如法炮制,因為 JavaScript 是運行在單線程上的,其不會等待 c# 調用的結果,所以如何實現 confirm 框還是另想辦法吧
            await webView.InvokeScriptAsync("eval", new string[] { "window.alert = function (alertMessage) {window.external.notify('alert:' + alertMessage)}" });
        }
    }
}



OK
[源碼下載]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM