昨日の今日ではあるんですが、WebView2を使ってJavaScriptとC#を連携させる方法がわかったので、記事に残します。
(筆者の個人的な事情なんですが、Qiitaの記事作成が今日で三日連続です(笑)
今日は仕事終わりなので、サクッと記事を書いて終わりたい…(笑))
コーディング
とりあえず、サンプルのコードを下記に貼り付けます。
Form1.cs と JavaScriptを仕込んだ sample.htmlだけなので、察しの良い人ならサンプルのコードを見ただけで十分かもしれません。
(.htmlに関しては適当に書いたので、あまり深く突っ込まないでください(笑))
usingMicrosoft.Web.WebView2.Core;usingMicrosoft.Web.WebView2.WinForms;usingSystem;usingSystem.Runtime.InteropServices;usingSystem.Windows.Forms;namespaceSampleWebView2Form{publicpartialclassForm1:Form{/// <summary>webviewのコントロール(わかりやすい様に、デザイナーを使わずにコード側で実装します。)</summary>privateWebView2WebView=newWebView2{//個人の環境に合わせて下さいSource=newUri("file:///C:/Users/name/Desktop/sample.html"),};/// <summary>JavaScriptで呼ぶ関数を保持するオブジェクト</summary>privateJsToCsCsClass=newJsToCs();publicForm1(){this.Controls.Add(WebView);InitializeComponent();//WebView2のサイズをフォームのサイズに合わせるWebView.Size=this.Size;this.SizeChanged+=Form1_SizeChanged;//WebView2のロード完了時のイベントWebView.NavigationCompleted+=WebView_NavigationCompleted;}/// <summary>WebView2のロード完了時</summary>privatevoidWebView_NavigationCompleted(objectsender,CoreWebView2NavigationCompletedEventArgse){try{if(WebView.CoreWebView2!=null){//JavaScriptからC#のメソッドが実行できる様に仕込むWebView.CoreWebView2.AddHostObjectToScript("class",CsClass);//JavaScriptの関数を実行CsToJs();}elseMessageBox.Show("CoreWebView2==null");}catch(Exceptionex){MessageBox.Show(ex.ToString());}}/// <summary>Jsのメソッドを実行</summary>privateasyncvoidCsToJs(){//WebView.ExecuteScriptAsync("func1()").ResultをするとWebView2がフリーズするstringstr1=awaitWebView.ExecuteScriptAsync("func1(\"C#からの呼び出し\")");MessageBox.Show("Jsからの戻り値>"+str1);}/// <summary>サイズ変更時のイベントでWebView2のサイズをフォームに合わせる</summary>privatevoidForm1_SizeChanged(objectsender,EventArgse){WebView.Size=this.Size;}}//↓属性設定が無いとエラーになります/// <summary>WebView2に読み込ませるためのJsで実行する関数を保持させたクラス</summary>[ClassInterface(ClassInterfaceType.AutoDual)][ComVisible(true)]publicclassJsToCs{publicvoidMessageShow(stringstrText){MessageBox.Show("Jsからの呼び出し>"+strText);}}}<!DOCTYPE html><htmllang="ja"><head><metacontent="text/html;charset=utf-8"http-equiv="Content-Type"/><script language="javascript"type="text/javascript">//C#から呼び出すための関数functionfunc1(str1){alert("C# called>"+str1);return"success"}functionButtonClick(){//C#の関数の実行chrome.webview.hostObjects.class.MessageShow("Js send text");}</script></head><body><h1>wasm_sample</h1><inputtype="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>privateasyncvoidCsToJs(){//WebView.ExecuteScriptAsync("func1()").ResultをするとWebView2がフリーズするstringstr1=awaitWebView.ExecuteScriptAsync("func1(\"C#からの呼び出し\")");MessageBox.Show("Jsからの戻り値>"+str1);}<script language="javascript"type="text/javascript">//C#から呼び出すための関数functionfunc1(str1){alert("C# called>"+str1);return"success"}</script>挙動としては下記画像の様になります。
・ロード直後にJavaScriptのアラート出力
・アラートを閉じると、メッセージボックス出力
JavaScript->C#
JavaScriptからC#の呼び出しには、AddHostObjectToScript()を使ってC#内で作成した関数をJavaScriptに読み込ませます。
(WebMessageReceivedを使う方法もあるらしいので、気になる方は調べてみてください)
サンプルコードでは、下記の部分が該当の箇所です。
/// <summary>JavaScriptで呼ぶ関数を保持するオブジェクト</summary>JsToCsCsClass=newJsToCs();//JavaScriptからC#のメソッドが実行できる様に仕込むWebView.CoreWebView2.AddHostObjectToScript("class",CsClass);//~~~一部省略~~~/// <summary>WebView2に読み込ませるためのJsで実行する関数を保持させたクラス</summary>[ClassInterface(ClassInterfaceType.AutoDual)][ComVisible(true)]publicclassJsToCs{publicvoidMessageShow(stringstrText){MessageBox.Show("Jsからの呼び出し>"+strText);}}<script language="javascript"type="text/javascript">functionButtonClick(){//C#の関数の実行chrome.webview.hostObjects.class.MessageShow("Js send text");}</script><body><inputtype="button"value='send Message'onclick="ButtonClick();"/></body>挙動としては、ブラウザー内の「send Message」を押下してもらうと、C#のメッセージが出力される様になっています。
まとめ
今回はこんなところです。
WebView2に関しての記事は昨日書いたのですが、JavaScriptからC#を実行する処理に関しては直近一週間くらい、ずっと放置だったので、その問題が解消して良かったです。
今日は特に書くことないですね(別に無くても良いんですが(笑))
昨日書いた記事のリンクを一応貼り付けときます。
https://qiita.com/NagaJun/items/4925a63ce7b93b80639e
最後まで読んで頂き、ありがとうございました。