昨日の今日ではあるんですが、WebView2を使ってJavaScriptとC#を連携させる方法がわかったので、記事に残します。
(筆者の個人的な事情なんですが、Qiitaの記事作成が今日で三日連続です(笑)
今日は仕事終わりなので、サクッと記事を書いて終わりたい…(笑))
##コーディング
とりあえず、サンプルのコードを下記に貼り付けます。
Form1.cs と JavaScriptを仕込んだ sample.htmlだけなので、察しの良い人ならサンプルのコードを見ただけで十分かもしれません。
(.htmlに関しては適当に書いたので、あまり深く突っ込まないでください(笑))
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);
}
}
}
<!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 なので、戻り値を取得する場合は.Result
かawait
を使用することになるのですが、.Result
を使用するとフリーズして処理が進まなくなるため、戻り値を取得するならawait
を使用する必要があります。
サンプルコードでは、下記の部分が該当の箇所です。
/// <summary>Jsのメソッドを実行</summary>
private async void CsToJs()
{
//WebView.ExecuteScriptAsync("func1()").ResultをするとWebView2がフリーズする
string str1 = await WebView.ExecuteScriptAsync("func1(\"C#からの呼び出し\")");
MessageBox.Show("Jsからの戻り値>" + str1);
}
<script language="javascript" type="text/javascript">
//C#から呼び出すための関数
function func1(str1) {
alert("C# called>" + str1);
return "success"
}
</script>
挙動としては下記画像の様になります。
・ロード直後にJavaScriptのアラート出力
・アラートを閉じると、メッセージボックス出力
JavaScript->C#
JavaScriptからC#の呼び出しには、AddHostObjectToScript()
を使ってC#内で作成した関数をJavaScriptに読み込ませます。
(WebMessageReceived
を使う方法もあるらしいので、気になる方は調べてみてください)
サンプルコードでは、下記の部分が該当の箇所です。
/// <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);
}
}
<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#のメッセージが出力される様になっています。
##まとめ
今回はこんなところです。
WebView2に関しての記事は昨日書いたのですが、JavaScriptからC#を実行する処理に関しては直近一週間くらい、ずっと放置だったので、その問題が解消して良かったです。
今日は特に書くことないですね(別に無くても良いんですが(笑))
昨日書いた記事のリンクを一応貼り付けときます。
https://qiita.com/NagaJun/items/4925a63ce7b93b80639e
最後まで読んで頂き、ありがとうございました。