デスクトップアプリにWebブラウザを組み込むと、Webサイトのコンテンツを画面に表示したり、様々な操作が可能になります。
そして、WebView2を使うことで、自作アプリにMicrosoft Edgeブラウザと同等の機能を組み込むことができます。
この記事では、WebView2の概要、インストール方法と基本的な使い方をコード付きで紹介します。
WebView2で自作アプリにブラウザを組み込んで、Webとネイティブの融合を体験しましょう!
WebView2とは
WebView2とは、Microsoft Edgeのレンダリングエンジンを利用して、デスクトップアプリにWebコンテンツを表示できるコントロールであり、その内部にはオープンソースのブラウザ向けコードベース「Chromium」が使われています。
WebView2は、Win32 C/C++、.NET Framework、.NET Core、.NET 5、.NET 6、WinUI 2.0、WinUI 3.0などのプログラミング環境で使用でき、Windows 10とWindows 11のほとんどのバージョンで動作します。
WebView2には、2種類の配布モードが用意されており、1つは定期的に最新のChromiumに更新される「Evergreen」モード、もう1つは特定のChromiumバージョンに固定して組み込む「Fixed」です。
Chromiumとは
Chromiumとは、ブラウザを開発する上で必要なプログラムコードの集まり、通称「コードベース」であり、Googleによって開発とメンテナンスが行なわれています。
Chromiumはオープンソースとして公開されており、Google Chromeはもとより、Microsoft Edge、brage、Opera、VIVALDIなど多くのブラウザで利用されています。
WebViewとWebView2について
WebViewとは、アプリ内にブラウザのような機能を埋め込み、アプリの中でWebサイトを表示できるようにする技術のことです。
WebViewは、主にスマートフォンやタブレットなどのモバイルデバイス向けのアプリで使用されています。アプリ内にWebページを表示することで、アプリの機能拡張やユーザーエクスペリエンスの向上を図ることができます。
具体的な例としては、以下のようなものに活用されています。
- ショッピングアプリで商品の詳細ページを表示する
- ニュースアプリで最新ニュースを表示する
- ゲームアプリでWeb広告を表示する
- 地図アプリでGoogleマップを表示する
WebView2 は WebView の技術を、内部に Chromium を使ってWindows向けに開発したものです。ちなみに、Androidも Chromium を採用していますが、iOSはWebViewとWebKitと呼ばれるコードベースが採用されています。
WebView2の特徴とメリット
WebView2の特徴とメリットを簡単にまとめておきます。
特徴 | メリット |
---|---|
Chromiumベースの最新のWeb技術をサポート | 最新のWebブラウザと同等のWebコンテンツを表示できる |
ネイティブアプリに組み込むことができる | ネイティブアプリにWebコンテンツを埋め込むことで、アプリの機能拡張やユーザーエクスペリエンスの向上が可能 |
エバーグリーン配布が可能 | アプリの更新時にWebView2ランタイムも自動的に更新されるため、開発者はアプリの更新に伴うWebView2ランタイムの更新作業をする必要がない |
ネイティブ機能への制御されたアクセスが可能 | WebView2アプリは、ネイティブ機能への制御されたアクセスを許可することで、強力で安全なアプリケーションを構築できる |
WebView2の動作環境
WebView2が動作するOSは次の通りです。
Windowsのバージョン |
---|
Windows 11 |
Windows 10 |
Windows 10 IoT Enterprise LTSC x32 2019 |
Windows 10 IoT Enterprise LTSC x64 2019 |
Windows 10 IoT Enterprise 21h1 x64 |
Windows Server 2022 |
Windows Server 2019 |
Windows Server 2016 |
SDKとVisual Studioのバージョンは次の通りです。
SDK | 必要なVisual Studioのバージョン |
---|---|
Win32 C/C++ SDK | Visual Studio 2015以降 |
.NET Framework SDK | Visual Studio 2017以降 |
.NET Core SDK | Visual Studio 2019以降 |
.NET 5 SDK | Visual Studio 2019以降 |
.NET 6 SDK | Visual Studio 2022以降 |
WinUI 2.0 SDK | Visual Studio 2019以降 |
WinUI 3.0 SDK | Visual Studio 2019以降 |
WebView2のインストール方法
Nugetから WebView2 を検索し、 「Microsoft.Web.WebView2」を選らんでインストールして下さい。Nugetに関する詳細と使い方については「Visual Studio のパッケージ管理機能 NuGetとは?」の記事で解説しています。
インストールが完了したら、レイアウトエディタからWebView2を選んで画面にドラッグ&ドロップするだけです。
WebView2の基本的な使い方
WebView2を使う場合は以下の手順が必要です。
WebView2に対して、Navigateメソッドに移動先のURLを指定することでページが表示されます。
ページの読み込みは非同期で行われるため、初期化のタイミングでページ読み込み完了のイベントハンドラを登録しておきます。
ページ読み込みが完了したら、ExecuteScriptAsyncメソッドで任意のJavaScriptを実行します。これにより、WebView2が表示しているDOM(Document Object Model)から情報を取得したり、値の設定やクリックなどの制御を行います。
WebView2のコード例
まずは、URLを入力するテキストボックスと、WebView2コントロールを張り付けただけの画面を使って基本的な使い方を解説します。
WebView2コントロールに "uxWebBrowser" 、アドレス入力用テキストボックスに "uxAddressBar" という名前を付けていることを前提に説明します。
初期化処理は非同期で行う必要があります。このため直接コンストラクタに記述できないので、下記のようなメソッドにしてコンストラクタ、又は Loadedイベントの中で呼び出します。
1 2 3 4 5 6 7 |
async void InitializeAsync() { // CoreWebView2が初期化されるまで待機 await uxWebBrowser.EnsureCoreWebView2Async(null); // ナビゲーションが完了したときのイベントハンドラーを追加 uxWebBrowser.NavigationCompleted += uxWebBrowser_NavigationCompleted; } |
ナビゲーション(ページ読み込み)が完了した時に呼ばれるイベントハンドラ内で、e.IsSuccessプロパティが trueになっていることを確認します。この例では、遷移先のURLを画面のテキストボックス(uxAddressBar)に表示しています。
1 2 3 4 5 6 7 8 9 |
private void uxWebBrowser_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) { //読み込み結果を判定 if (e.IsSuccess) { // ナビゲーションが成功した場合、現在のURLをアドレスバーに表示 uxAddressBar.Text = uxWebBrowser.CoreWebView2.Source; } } |
任意のページに移動するにはCoreWebView2.Navigate() メソッドを使います。引数にURLをセットするのですが、下記のサンプルはそれをメソッド化した例になります。
1 2 3 4 5 |
public void Navigate(string url) { // ウェブブラウザで指定されたURLにナビゲート uxWebBrowser.CoreWebView2.Navigate(url); } |
サンプルプログラムの全ソースコード
XAMLのサンプル全体は次の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WebView2Demo" xmlns:Wpf="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf" x:Class="WebView2Demo.MainWindow" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <DockPanel LastChildFill="True"> <TextBox x:Name="uxAddressBar" TextWrapping="NoWrap" Text="https://google.com" KeyDown="uxAddressBar_KeyDown" DockPanel.Dock="Top" Margin="5"/> <Wpf:WebView2 x:Name="uxWebBrowser"/> </DockPanel> </Grid> </Window> |
C#のサンプル全体は次の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
using Microsoft.Web.WebView2.Core; using System; using System.Collections.Generic; using System.Linq; using System.Reflection.Metadata; using System.Security.Policy; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Xml.Linq; using static System.Net.Mime.MediaTypeNames; namespace WebView2Demo { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { // XAMLコンポーネントの初期化 InitializeComponent(); // 非同期での初期化処理を実行 InitializeAsync(); } /// <summary> /// WebView2の初期化処理 /// </summary> async void InitializeAsync() { // CoreWebView2が初期化されるまで待機 await uxWebBrowser.EnsureCoreWebView2Async(null); // ナビゲーションが完了したときのイベントハンドラーを追加 uxWebBrowser.NavigationCompleted += uxWebBrowser_NavigationCompleted; } /// <summary> /// 指定されたURLにナビゲートします。 /// </summary> /// <param name="url">ナビゲート先のURL。</param> public void Navigate(string url) { // ウェブブラウザで指定されたURLにナビゲート uxWebBrowser.CoreWebView2.Navigate(url); } /// <summary> /// ナビゲーションが完了したときに呼び出されるイベント処理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void uxWebBrowser_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e) { //読み込み結果を判定 if (e.IsSuccess) { // ナビゲーションが成功した場合、現在のURLをアドレスバーに表示 uxAddressBar.Text = uxWebBrowser.CoreWebView2.Source; } } /// <summary> /// キーが押された時の処理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void uxAddressBar_KeyDown(object sender, KeyEventArgs e) { if(e.Key == Key.Enter) { Navigate(uxAddressBar.Text); } } } } |
WebView2の応用的な使い方
次は応用例として、表示されたウェブページから、自動的にLink,img,input,head,body タグを抜き出して表示すると共に、任意のJavaScriptを実行するサンプルプログラムについて紹介します。
尚、開発ツールとFrameworkは次の通りです。
開発ツール | Visual Studio Community 2022 (64bit) Version 17.8.2 |
---|---|
Framework | .NET Core 6.0 |
あくまでもサンプルなので、アドレスバーでエンターキーを押す操作に対応していなかったり、何らかの操作でエラーになるかもしれませんがご容赦下さい。
プロジェクトは下記からダウンロードできます。ダウンロードしたら、WebView2をNugetからインストールしてお使いください。
WebView2Demoプロジェクト
サンプルソース一式
今回はMicrosoftから配布されているVisual Studio用のアイコンを使っています。プロジェクトの中に同梱しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WebView2Demo" xmlns:Wpf="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf" x:Class="WebView2Demo.MainWindow" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <!-- ボタンのスタイルを定義 --> <Style TargetType="Button"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="FocusVisualStyle" Value="{x:Null}"/> <Setter Property="Height" Value="16"/> <Setter Property="Margin" Value="5"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Opacity" Value="0.5"/> <Setter Property="Background" Value="Transparent"/> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="LightGray"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="104*"/> <ColumnDefinition Width="5"/> <ColumnDefinition Width="55*"/> </Grid.ColumnDefinitions> <DockPanel LastChildFill="True" Grid.Column="0" Background="#efefff"> <DockPanel DockPanel.Dock="Top"> <!-- 各ボタンのインスタンスを作成し、Styleと画像を指定 --> <Button Command="{x:Static local:MainWindow.GoBackCommand}"> <Image Source="Image/arrow_Previous_16xLG_color.png" /> </Button> <Button Command="{x:Static local:MainWindow.GoForwardCommand}"> <Image Source="Image/arrow_Next_16xLG_color.png" /> </Button> <Button Command="{x:Static local:MainWindow.RefreshCommand}"> <Image Source="Image/Refresh_grey_16x.png" /> </Button> <Button Command="{x:Static local:MainWindow.NavigateCommand}" DockPanel.Dock="Right"> <Image Source="Image/Search_glyph71GrayNoHalo_16x.png" /> </Button> <TextBox x:Name="uxAddressBar" TextWrapping="NoWrap" Text="https://google.com" VerticalAlignment="Center" Margin="5" /> </DockPanel> <Wpf:WebView2 x:Name="uxWebBrowser"/> </DockPanel> <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch"></GridSplitter> <DockPanel Grid.Column="2" Margin="5"> <Button DockPanel.Dock="Top" Command="{x:Static local:MainWindow.ExecJavaScriptCommand}" HorizontalAlignment="Left" Width="120" Height="20" BorderThickness="1"> <StackPanel Orientation="Horizontal"> <TextBlock Text="JavaScriptの実行" Margin="0,0,5,0"></TextBlock> <Image Source="Image/Run_16x.png"></Image> </StackPanel> </Button> <TextBlock Text="スクリプト" DockPanel.Dock="Top" ></TextBlock> <TextBox x:Name="uxJavaScript" Height="100" AcceptsReturn="True" DockPanel.Dock="Top" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/> <TabControl> <TabItem Header="結果"> <TextBox x:Name="uxResult" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/> </TabItem> <TabItem Header="Link"> <TextBox x:Name="uxLinkTag" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/> </TabItem> <TabItem Header="Image"> <TextBox x:Name="uxImageTag" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/> </TabItem> <TabItem Header="Input"> <TextBox x:Name="uxInputTag" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/> </TabItem> <TabItem Header="head"> <TextBox x:Name="uxHead" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/> </TabItem> <TabItem Header="body"> <TextBox x:Name="uxBody" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/> </TabItem> </TabControl> </DockPanel> </Grid> </Window> |
下記がC#のプログラム全体です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
using Microsoft.Web.WebView2.Core; using System; using System.Collections.Generic; using System.Linq; using System.Reflection.Metadata; using System.Security.Policy; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Xml.Linq; using static System.Net.Mime.MediaTypeNames; namespace WebView2Demo { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public static RoutedCommand GoBackCommand = new RoutedCommand(); public static RoutedCommand GoForwardCommand = new RoutedCommand(); public static RoutedCommand NavigateCommand = new RoutedCommand(); public static RoutedCommand RefreshCommand = new RoutedCommand(); public static RoutedCommand ExecJavaScriptCommand = new RoutedCommand(); public MainWindow() { // XAMLコンポーネントの初期化 InitializeComponent(); // 非同期での初期化処理を実行 InitializeAsync(); // コマンドごとの処理を定義 SetCommandBindings(); } /// <summary> /// WebView2の初期化処理 /// </summary> async void InitializeAsync() { // CoreWebView2が初期化されるまで待機 await uxWebBrowser.EnsureCoreWebView2Async(null); // ナビゲーションが完了したときのイベントハンドラーを追加 uxWebBrowser.NavigationCompleted += uxWebBrowser_NavigationCompleted; // 新しいウィンドウが要求されたときのイベントハンドラーを追加 uxWebBrowser.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested; } /// <summary> /// コマンド処理 /// </summary> private void SetCommandBindings() { // ウェブブラウザの履歴を戻るためのコマンド処理 CommandBindings.Add(new CommandBinding(GoBackCommand, (sender, e) => { if (uxWebBrowser.CanGoBack) uxWebBrowser.GoBack(); }, (sender, e) => e.CanExecute = uxWebBrowser.CanGoBack)); // ウェブブラウザの履歴を進むためのコマンド処理 CommandBindings.Add(new CommandBinding(GoForwardCommand, (sender, e) => { if (uxWebBrowser.CanGoForward) uxWebBrowser.GoForward(); }, (sender, e) => e.CanExecute = uxWebBrowser.CanGoForward)); // 指定されたURLに移動するためのコマンド処理 CommandBindings.Add(new CommandBinding(NavigateCommand, (sender, e) => Navigate(uxAddressBar.Text), (sender, e) => e.CanExecute = !string.IsNullOrEmpty(uxAddressBar.Text))); // ウェブブラウザのコンテンツを更新するためのコマンド処理 CommandBindings.Add(new CommandBinding(RefreshCommand, (sender, e) => uxWebBrowser.Reload(), (sender, e) => e.CanExecute = true)); // ウェブブラウザでJavaScriptを実行するためのコマンド処理 CommandBindings.Add(new CommandBinding(ExecJavaScriptCommand, async (sender, e) => uxResult.Text = await ExecuteJavaScriptAsync(uxJavaScript.Text), (sender, e) => e.CanExecute = uxJavaScript.Text.Length > 0)); } /// <summary> /// 指定されたURLにナビゲートします。 /// </summary> /// <param name="url">ナビゲート先のURL。</param> public void Navigate(string url) { try { // アドレスバーに検索クエリを含んだGoogleの検索URLを表示 uxAddressBar.Text = "https://www.google.com/search?q=" + Uri.EscapeDataString(url); // ウェブブラウザで指定されたURLにナビゲート uxWebBrowser.CoreWebView2.Navigate(url); } catch (Exception ex) { // エラーが発生した場合、メッセージボックスでエラーを表示 MessageBox.Show(ex.Message, "エラー", MessageBoxButton.OK, MessageBoxImage.Error); } } /// <summary> /// JavaScriptを実行する /// </summary> /// <param name="script"></param> /// <returns></returns> public async Task<string?> ExecuteJavaScriptAsync(string script) { try { // JavaScriptの実行 var result = await uxWebBrowser.CoreWebView2.ExecuteScriptAsync(script); // Json形式の戻り値を文字列に変換 return JsonSerializer.Deserialize<string>(result); } catch (Exception ex) { Console.WriteLine($"Failed to execute script: {ex.Message}"); return null; } } /// <summary> /// ナビゲーションが完了したときに呼び出されるイベント処理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void uxWebBrowser_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e) { //読み込み結果を判定 if (e.IsSuccess) { // ナビゲーションが成功した場合、現在のURLをアドレスバーに表示 uxAddressBar.Text = uxWebBrowser.CoreWebView2.Source; // HTMLを解析 Analyze(); } } /// <summary> /// 新しいウィンドウが要求されたときに呼び出されるイベントハンドラー。 /// </summary> /// <param name="sender">イベントの発生源。</param> /// <param name="e">新しいウィンドウの要求に関連するイベント データ。</param> private void CoreWebView2_NewWindowRequested(object? sender, CoreWebView2NewWindowRequestedEventArgs e) { // 新しいウィンドウの作成をキャンセル e.Handled = true; // 新しいウィンドウで開こうとしたURLを現在のウィンドウで開く uxWebBrowser.CoreWebView2.Navigate(e.Uri); } private async void Analyze() { uxHead.Text = await ExecuteJavaScriptAsync("document.head.outerHTML"); uxBody.Text = await ExecuteJavaScriptAsync("document.body.outerHTML"); uxLinkTag.Text = await ExecuteJavaScriptAsync(template("a","href")); uxImageTag.Text = await ExecuteJavaScriptAsync(template("img", "src")); uxInputTag.Text = await ExecuteJavaScriptAsync(template("input", "outerHTML")); string template(string s,string a) { return $@"Array.from(document.querySelectorAll('{s}')).map(i => i.{a}).join('\n')"; } } } } |
JavaScriptを使って値を取得する方法
CoreWebView2.ExecuteScriptAsyncメソッドの引数にJavaScriptを指定すると、結果が文字列として返されます。このメソッドは非同期なので注意して下さい。
1 |
var result = await uxWebBrowser.CoreWebView2.ExecuteScriptAsync(script) |
尚、戻り値はJson形式で帰ってくるので、文字列に変換する必要があります。そこで、サンプルプログラムではJavaScriptの実行結果を文字列に変換して返すようにメソッド化しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public async Task<string?> ExecuteJavaScriptAsync(string script) { try { // JavaScriptの実行 var result = await uxWebBrowser.CoreWebView2.ExecuteScriptAsync(script); // Json形式の戻り値を文字列に変換 return JsonSerializer.Deserialize<string>(result); } catch (Exception ex) { Console.WriteLine($"Failed to execute script: {ex.Message}"); return null; } } |
下記は、表示中のウェブページからタグの内容を抽出し、画面右のタブコントロールに表示するメソッドです。templaeというローカル関数を作っているので、タグとプロパティを変更するだけで好きな情報が簡単に抜き出せます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
private async void Analyze() { uxHead.Text = await ExecuteJavaScriptAsync("document.head.outerHTML"); uxBody.Text = await ExecuteJavaScriptAsync("document.body.outerHTML"); uxLinkTag.Text = await ExecuteJavaScriptAsync(template("a","href")); uxImageTag.Text = await ExecuteJavaScriptAsync(template("img", "src")); uxInputTag.Text = await ExecuteJavaScriptAsync(template("input", "outerHTML")); string template(string s,string a) { return $@"Array.from(document.querySelectorAll('{s}')).map(i => i.{a}).join('\n')"; } } |
JavaScriptを使って値を設定する方法
ウェブページに値を設定する方法も、CoreWebView2.ExecuteScriptAsyncメソッドの引数にJavaScriptを指定します。
例えば、価格.COMのノートパソコン製品一覧ページで以下の操作を行うとしましょう。
- 「フリーワード・一括件検索」欄に "HP"を入力
- LenovoのノードPCの「チェックボックス」にチェック
- 「絞り込み条件を一括追加・変更」ボタンをクリック
C#から WebView2にを使って直接JavaScriptを実行するには、次のように記述します。
1 2 3 4 5 6 7 8 9 |
await uxWebBrowser.CoreWebView2.ExecuteScriptAsync( "document.querySelector('.keywords').value='HP'" ); await uxWebBrowser.CoreWebView2.ExecuteScriptAsync( "document.querySelector('input[value=\"K0001543298\"').checked= true" ); await uxWebBrowser.CoreWebView2.ExecuteScriptAsync( "document.querySelector('#btSearhBySpec').click()" ); |
サンプルプログラムではExecuteJavaScriptAsyncというメソッドを用意していますので、次の様に記述出来ます。
1 2 3 |
await ExecuteJavaScriptAsync("document.querySelector('.keywords').value='HP'"); await ExecuteJavaScriptAsync("document.querySelector('input[value=\"K0001543298\"').checked= true"); await ExecuteJavaScriptAsync("document.querySelector('#btSearhBySpec').click()"); |
一方、サンプルプログラムの画面からJavaScriptを実行するには、次のように入力して「JavaScriptの実行」ボタンをクリックします。
1 2 3 |
document.querySelector('.keywords').value='HP' document.querySelector('input[value="K0001572962"').checked=true document.querySelector('#btSearhBySpec').click(); |
自作アプリを他のPCで動作させるには
WebView2をターゲット環境で動作させるには WebView2 のランタイムをインストールする必要がありますが、Windows10/11 で Microsoft Edge がインストールされている場合、別途インストールする必要はありません。
ただ、アプリに張り付けたWebView2コントロールとMicrosoft Edgeではエンジン更新タイミングが異なるため、両者のバージョンが異なることで、将来何らかの不具合が発生する可能性はあります。
常に最新を保つためにはエバーグリーン配布モードを使う必要がありますので、詳細はマイクロソフトの公式ページでご確認下さい。
ランタイムのインストーラは、こちらの公式ページからダウンロード可能です。
一番簡単な方法は、下記のリンクを自作アプリの先頭で実行することです。これにより、小さなエバーグリーン配布用のプログラムがインストールされ、以降は自動更新されるようになります。
1 |
https://go.microsoft.com/fwlink/p/?LinkId=2124703 |
このリンクをWebView2 で表示してあげればランタイムのインストール画面が表示され、インストールできます。例えば uxWebBrowserという名前でWebView2のコントロールを張り付けている場合は、次の様に記述します。
1 |
uxWebBrowser.Source = new System.Uri("https://go.microsoft.com/fwlink/p/?LinkId=2124703"); |
WebView2のランタイムがインストールされていなくても、WebView2を組み込んだ自作アプリ自身は起動され、インストーラのダウンロードを促してくれます。
まとめ
今回はWebView2のインストールと使い方についてサンプルソースコードを交えて解説しました。
WebViewはアプリ内にブラウザのような機能を埋め込み、アプリの中でWebサイトを表示できるようにする技術のことで、Microsoft が Windowsアプリ向けに開発したものが WebView2です。
WebView2は内部に Chromium というベースコードが用いられており、アプリからは JavaScriptを通してDOMにアクセスすることが可能です。
WebView2を使うと、デスクトップの自作アプリにMicrosoft Edgeと同等のブラウザ機能を組み込んで、スクレイピングやWebアプリとの連携などが簡単に実現できます。
Webには様々なサービスが公開されていますので、自作アプリから画面を操作すると活用範囲が大幅に広がる事でしょう。
是非皆さんもチャレンジしてみてください。
コメント