26
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WebView2 C#とJavaScriptの連携

Last updated at Posted at 2020-11-16

昨日の今日ではあるんですが、WebView2を使ってJavaScriptとC#を連携させる方法がわかったので、記事に残します。
(筆者の個人的な事情なんですが、Qiitaの記事作成が今日で三日連続です(笑)
今日は仕事終わりなので、サクッと記事を書いて終わりたい…(笑))
##コーディング
とりあえず、サンプルのコードを下記に貼り付けます。
Form1.cs と JavaScriptを仕込んだ sample.htmlだけなので、察しの良い人ならサンプルのコードを見ただけで十分かもしれません。
(.htmlに関しては適当に書いたので、あまり深く突っ込まないでください(笑))

Form1.cs
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace SampleWebView2Form
{
    public partial class Form1 : Form
    {
        /// <summary>webviewのコントロール(わかりやすい様に、デザイナーを使わずにコード側で実装します。)</summary>
        private WebView2 WebView = new WebView2
        {
            //個人の環境に合わせて下さい
            Source = new Uri("file:///C:/Users/name/Desktop/sample.html"),
        };

        /// <summary>JavaScriptで呼ぶ関数を保持するオブジェクト</summary>
        private JsToCs CsClass = new JsToCs();

        public Form1()
        {
            this.Controls.Add(WebView);
            InitializeComponent();

            //WebView2のサイズをフォームのサイズに合わせる
            WebView.Size = this.Size;
            this.SizeChanged += Form1_SizeChanged;

            //WebView2のロード完了時のイベント
            WebView.NavigationCompleted += WebView_NavigationCompleted;
        }

        /// <summary>WebView2のロード完了時</summary>
        private void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
        {
            try
            {
                if (WebView.CoreWebView2 != null)
                {
                    //JavaScriptからC#のメソッドが実行できる様に仕込む
                    WebView.CoreWebView2.AddHostObjectToScript("class", CsClass);

                    //JavaScriptの関数を実行
                    CsToJs();
                }
                else MessageBox.Show("CoreWebView2==null");
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        /// <summary>Jsのメソッドを実行</summary>
        private async void CsToJs()
        {
            //WebView.ExecuteScriptAsync("func1()").ResultをするとWebView2がフリーズする
            string str1 = await WebView.ExecuteScriptAsync("func1(\"C#からの呼び出し\")");
            MessageBox.Show("Jsからの戻り値>" + str1);
        }

        /// <summary>サイズ変更時のイベントでWebView2のサイズをフォームに合わせる</summary>
        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            WebView.Size = this.Size;
        }
    }

    //↓属性設定が無いとエラーになります
    /// <summary>WebView2に読み込ませるためのJsで実行する関数を保持させたクラス</summary>
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class JsToCs
    {
        public void MessageShow(string strText)
        {
            MessageBox.Show("Jsからの呼び出し>" + strText);
        }
    }
}
sample.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
    <script language="javascript" type="text/javascript">
        //C#から呼び出すための関数
        function func1(str1) {
            alert("C# called>" + str1);
            return "success"
        }
        function ButtonClick() {
            //C#の関数の実行
            chrome.webview.hostObjects.class.MessageShow("Js send text");
        }
    </script>
</head>
<body>
    <h1>sample</h1>
    <input type="button" value='send Message' onclick="ButtonClick();"/>
    <script></script>
</body>
</html>

##解説
C#->JavaScript
C#からJavaScript内の関数を呼び出すには、ExecuteScriptAsync()を使います。この関数は、先日書いた記事でExecuteScriptAsync("alert(\"message\")");的な使い方をしたのですが、引数の中身がJavaScriptとして処理できるのであれば、JavaScriptのコード内の独自で作成した関数でも実行できます。
注意点として、ExecuteScriptAsync()は Task なので、戻り値を取得する場合は.Resultawaitを使用することになるのですが、.Resultを使用するとフリーズして処理が進まなくなるため、戻り値を取得するならawaitを使用する必要があります。
サンプルコードでは、下記の部分が該当の箇所です。

Form1.cs
        /// <summary>Jsのメソッドを実行</summary>
        private async void CsToJs()
        {
            //WebView.ExecuteScriptAsync("func1()").ResultをするとWebView2がフリーズする
            string str1 = await WebView.ExecuteScriptAsync("func1(\"C#からの呼び出し\")");
            MessageBox.Show("Jsからの戻り値>" + str1);
        }
sample.html
    <script language="javascript" type="text/javascript">
        //C#から呼び出すための関数
        function func1(str1) {
            alert("C# called>" + str1);
            return "success"
        }
    </script>

挙動としては下記画像の様になります。
・ロード直後にJavaScriptのアラート出力
image.png
・アラートを閉じると、メッセージボックス出力
image.png
JavaScript->C#
JavaScriptからC#の呼び出しには、AddHostObjectToScript()を使ってC#内で作成した関数をJavaScriptに読み込ませます。
WebMessageReceivedを使う方法もあるらしいので、気になる方は調べてみてください)
サンプルコードでは、下記の部分が該当の箇所です。

Form1.cs
        /// <summary>JavaScriptで呼ぶ関数を保持するオブジェクト</summary>
        JsToCs CsClass = new JsToCs();
        //JavaScriptからC#のメソッドが実行できる様に仕込む
        WebView.CoreWebView2.AddHostObjectToScript("class", CsClass);

//~~~一部省略~~~
    /// <summary>WebView2に読み込ませるためのJsで実行する関数を保持させたクラス</summary>
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class JsToCs
    {
        public void MessageShow(string strText)
        {
            MessageBox.Show("Jsからの呼び出し>" + strText);
        }
    }
sample.html
    <script language="javascript" type="text/javascript">
        function ButtonClick() {
            //C#の関数の実行
            chrome.webview.hostObjects.class.MessageShow("Js send text");
        }
    </script>

<body>
    <input type="button" value='send Message' onclick="ButtonClick();"/>
</body>

挙動としては、ブラウザー内の「send Message」を押下してもらうと、C#のメッセージが出力される様になっています。
image.png
##まとめ
今回はこんなところです。
WebView2に関しての記事は昨日書いたのですが、JavaScriptからC#を実行する処理に関しては直近一週間くらい、ずっと放置だったので、その問題が解消して良かったです。

今日は特に書くことないですね(別に無くても良いんですが(笑))
昨日書いた記事のリンクを一応貼り付けときます。
https://qiita.com/NagaJun/items/4925a63ce7b93b80639e
最後まで読んで頂き、ありがとうございました。

26
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?