WebView2 で自分好みのブラウザを作る

# 〇 はじめに
本記事は、 Microsoft Azure Tech | Advent Calendar 2022 20 日目の記事です。
…今日はクリスマスイブですが、Advent Calendar 20 日目の記事となります。

Web を閲覧する際に利用するソフトをブラウザと言いますが、
「本当にベストなもの」というのは個々の感性によって大きく違いが出るかと思います。
なので、「ああいうブラウザがあればいいのになぁ」とは誰もが一度は考えることでしょう。(そうか？
とはいっても、一からブラウザを設計し、また実装も行うというのは限られた一部のエンジニアにしかできないことです。

本記事は一からとは言わないものの、"WebView2" というコンポーネントを利用することで、
プログラミング初心者でも可能なレベルでのお手軽さでブラウザを作ってみよう、という内容になります。
開発環境及び動作環境は Windows 系 OS + Visual Studio 2022 、言語は C# としています。

なお、Win32 用 Project でも大体流れは同じですが、参考に適しているのは [こちら](https://learn.microsoft.com/en-us/microsoft-edge/webview2/get-started/win32) となります。
また、今回は実装面で [WebView2 SDK](https://learn.microsoft.com/ja-jp/microsoft-edge/webview2/release-notes?tabs=dotnetcsharp) の話は割愛して Runtime だけとします。

# 〇 WebView2 とは
[公式](https://learn.microsoft.com/ja-jp/microsoft-edge/webview2/)

The Microsoft Edge WebView2 control allows you to embed web technologies (HTML, CSS, and JavaScript) in your native apps. 
(Microsoft Edge WebView2 コントロールを使用することで、HTML、CSS、および JavaScript などの Web Technology をネイティブ アプリに埋め込むことが可能です。

The WebView2 control uses Microsoft Edge as the rendering engine to display the web content in native apps.
(WebView2 Controlは Microsoft Edgeをレンダリング エンジンとして使用してネイティブ アプリ上で Webコンテンツを表示するものです)

With WebView2, you can embed web code in different parts of your native app, or build all of the native app within a single WebView2 instance.
(WebView2 ではネイティブ アプリに Web Code を異なった場所に埋め込んだり、Single な WebView2 Instance にネイティブ アプリを構築することが可能です)

上記のように、 WebView2 は コントロール コンポーネントです。
IDE から利用する場合、見かけ上の実体 (SDK) としては WebView2.Runtime.Xxx となります。
デフォルトではプロジェクトに含まれませんので、Nuget Package Manager からインストールするのが簡単です。

# 〇 とりあえず作ってみる
## 1.プロジェクトの作成
Visual Studio を立ち上げ、 以下手順通りにプロジェクトを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/ce054907-8700-f1ad-02b8-fb570d3be775.png)

テンプレートは Windows Form App (.NET 用) を指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/5441f148-2a54-f514-68e6-18be0482799b.png)

プロジェクト名は任意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/ab81e714-9c7b-8215-2c51-7229315c82ed.png)

フレームワークはそのまま .NET 6.0。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/68ae30f6-e602-7026-8b5a-4c910f84e206.png)

以上でプロジェクトが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/de3f7b8c-d98c-db5c-5116-5ba4c14fab6c.png)

## 2. パッケージの登録設定
WebView2 用のパッケージ (WebView2 Runtime) をプロジェクトに登録していきます。
[ツール] - [NuGet パッケージ マネージャー] - [ソリューションの NuGet パッケージの管理] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/e75169c9-547a-d77a-96f3-b84db3e2e4b6.png)

新規に [NuGet - ソリューション] タブが開かれますので、[参照] を選択後、WebView2 Runtime の検索を行います。
OS に適切な Runtime を選択後、 [インストール] ボタンを押下し、しばらく待機してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/4986d2dc-a6e3-7692-1a85-1a30766eb637.png)

(正常にインストールされた場合)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/c0ca0a3d-0fa9-3b2d-1d0a-fa6236110cba.png)

この状態で Form1 のデザイン ビューに戻ると、ツールボックスに WebView2 コントローラが追加されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/f8513a1e-97e5-e64a-e4b6-e46d21440187.png)

## 3. コントローラを配置し、 Webにアクセスしてみる。
「TextBox で Enter を押すと、入力している URL にジャンプする」 だけのアプリを作ります。
TextBox と WebView2 コントローラを一つずつ配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/8e660ab1-eaaa-2b8a-f207-0522a0631398.png)

TextBox にボタン押下時のイベントを追加します。
テキストボックスを選択し、プロパティの雷マーク(?) を押下し、 "TextChanged" イベントを探しダブルクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/4db4aa16-8c6c-773c-71f7-252b37c0d654.png)

コード ビューにジャンプされ、 textBox1_KeyDown() イベントが作成されますので、
Key 種別が Enter の場合に WebView2 コントローラのソースが書き換える処理を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/81dfe4ef-5162-04fc-56bc-d6c3675be009.png)

```C#:form1.cs
using System.Security.Policy;

namespace WebView2_TestApps
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.KeyCode == Keys.Enter && textBox1.Text != string.Empty)
            {                
                this.webView21.Source = new Uri(textBox1.Text);
            }
        }
    }
}
```


(F5 を押してプログラムをデバッグ起動)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/802721e5-3421-00cd-d623-d9e409b553ad.png)

Form1 アプリが立ち上がってきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/3223127a-4137-c526-28da-e26d2beb3a12.png)

(取り合えず弊社 HP アドレスを入力し、Enter キーを押下)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/cf9a603e-3d56-0d44-5ead-a722a082f2f1.png)

WebView2 コントローラ部にサイトが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/699d77c3-84ee-b44a-7757-aeb98bf608da.png)

## 4. 戻る / 進むボタンを付けてみる
ブラウザでよく使う機能の一つが 戻る / 進むボタンですが、こちらを追加します。
レイアウトをまず適当に設定。 (なお Prev なら Next、 Forward なら Back と統一すべきでしたね。恥。だが直しません)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/65971426-b467-83f9-03b6-4782dda31731.png)

ボタンにイベントを付けていきます。後多少の実装を。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/1e6f6d52-fcf2-a967-229f-4a48213ab9a3.png)

```C#:form1.cs
using System.Security.Policy;

namespace WebView2_TestApps
{
    public partial class Form1 : Form
    {
        string currentUrl { get { return textBox1.Text; } }

        public Form1()
        {
            InitializeComponent();
        }

        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.KeyCode == Keys.Enter && currentUrl != string.Empty)
            {                
                webView21.Source = new Uri(currentUrl);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (webView21.CanGoBack)
            {
                webView21.GoBack();
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            if (webView21.CanGoForward)
            {
                webView21.GoForward();
            }
        }

        private void webView21_SourceChanged(object sender, Microsoft.Web.WebView2.Core.CoreWebView2SourceChangedEventArgs e)
        {
            button1.Enabled = webView21.CanGoBack;
            button2.Enabled = webView21.CanGoForward;

            currentUrl=webView21.Source.ToString();
        }
    }
}
```
(F5 で起動後)
今度は Qiita に行ってみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/c8bd545d-5c76-c3fc-b1b0-5a770fc603b0.png)

表示されたページから [質問] をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/29f3b05e-4d1c-a2cc-1166-1399a6042f6c.png)

Prev ボタンが活性化しました。押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/3fb8ee18-67fc-6fd9-cd01-e9e6dbec5ab1.png)

元のページに戻ってきました。と同時に Forward ボタンが今度は活性化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/2253f657-58c7-156b-ee3c-054d3854ed39.png)

 ----

という感じで、非常に少ないコードでブラウザとしての体裁が整うことがお分かりいただけると思います。
後はタブを追加したり、レジストリを読み込む機能を作り設定によって振る舞いを変えたり…
などということをしていくことで、好きなようにブラウザを構成していくことが出来るわけですね。

# 〇 WebView2 Runtime
作成手順の際に出てきた WebView2 Runtime。
これが今回の手順の核であることは容易に想像可能かと思いますが、いったいこれは何なのでしょうか。

## Microsoft Edge と WebView2 の違い

[公式](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/browser-features)

結論から言うと、 WebView2 Runtime は Microsoft Edge ほぼそのものです。
正確にいうなれば、 Edge に WebView2 SDK からアクセスするためのインターフェースがつけられたものです。

## 補遺 : WebView2 SDK
[公式](https://learn.microsoft.com/ja-jp/microsoft-edge/webview2/release-notes?tabs=dotnetcsharp)

WebView2 SDK は、クライアントアプリケーション側で作成される WebView2 のための API 群です。
SDK を利用した開発の場合は クライアント アプリ としてコンパイルされる実行可能ファイルの中に、
WebView2 SDK の API が埋め込まれる形となります。
SDK の API は Runtime のインターフェースを経由して  "WebView2 Runtime の中にある Edge" を操作します。



## Runtime の種別と配布条項
WebView2 には二種類の Runtime が存在します。

:::note info
・ Fix Version
Static Version / 固定バージョンとも。文字通り、固定のバージョンで配布される Runtime です。
自動での更新はなされません。

・ Evergreen
ネットワーク接続環境下において、定期的に最新化を試みる Runtime です。
ドメイン環境に限り、更新をポリシーにて制御可能です。
:::
これらの Runtime を同居させることも可能です。

なお、自分用のアプリを配布するならば特に考えなくてよいことですが、
第3者に提供する場合には提供者は以下の義務があります。

:::note info
- Fix Version か Evergreen(Auto Update) のいずれかの Runtime の配布
- Runtime のアップデート方法
:::
要は、どちらの種類の Runtime を扱うか、Fix の場合は更新時はどう配布するかを考える必要があるということです。

## インストール
プリインストール / 手動インストール / 自動インストール の三種類の方法が存在します。

Windows 10 が発表された当初は、 Microsoft Edge は Chromium ベースのものではない Legacy Edge と呼ばれるものでした。
(Legacy Edge はすでに廃止済みで Chromium Edge と互換性はありません)
このため、 Chromium Edge の技術で構成される WebView2 も当初はインストールされていないため、
多くの環境では手動インストールする必要がありました。

なお、WSUS を利用したインストールは残念ながら Windows Update カタログに存在しないため実施できません。

### プリインストール
コンシューマー向け Windows10 は [2022/07 より順次](https://blogs.windows.com/msedgedev/2022/06/27/delivering-the-microsoft-edge-webview2-runtime-to-windows-10-consumers/)、Windows 11 ではプリインストールされています。
また、Enterprise 用 Windows10 についても Windows Update によるプリインストールが間もなく開始される予定ですので、
基本的には Windows10 - 11 の環境でデフォルトでインストールされるようになります。

なお、サーバー OS にこの予定はありません。

### 自動インストール
Runtime を利用するアプリケーションを実行する際に、自動で実施されます。
例としては Microsoft 365 環境にアクセス時、Runtime が未インストールの場合に実施されます。

配布されるアプリケーションに依存したインストール方法ですので、
どのような場合に実施されるかを把握する方法はありません。
(このインストール方法により、身に覚えのない WebView2 がインストールされている、という話もちらほら…)

### 手動インストール
[こちら](https://developer.microsoft.com/ja-jp/microsoft-edge/webview2/)でインストーラが配布されています。
なお、公式配布バージョンの履歴は少ないですが、表示されているもの以外を入手する公式の方法はありません。

## アップデート
アプリ開発者が固定バージョンを指定している場合、アプリ開発者が更新時に配布する必要があります。
Evergreen 利用時の場合は各端末の [WebView2 用ポリシー](https://docs.microsoft.com/en-us/deployedge/microsoft-edge-update-policies#microsoft-edge-webview)に従います。

なお、更新の制御はドメイン参加端末でのみ可能です。
一方で、ドメイン参加端末であれば利用ユーザーがローカルアカウントでもこれらのポリシーは有効です。

### ・更新用エンドポイント
WebView2 の更新は [Edge 本体と同じエンドポイント](https://docs.microsoft.com/ja-jp/deployedge/microsoft-edge-security-endpoints#download-locations-for-microsoft-edge)です。

### ポリシー
一部の更新ポリシーとWebView2 用のポリシーを除き、Microsoft Edge のポリシーの影響を受けません。
なお、下記の2種の WebView2 専用以外のポリシーについては例外的に反映されます。

・[Microsoft Edge でのコンポーネントの更新を有効にする](https://learn.microsoft.com/ja-jp/deployedge/microsoft-edge-policies#componentupdatesenabled)
・[自動更新チェック期間のオーバーライド](https://learn.microsoft.com/ja-jp/deployedge/microsoft-edge-update-policies#autoupdatecheckperiodminutes)

### サポータビリティ
Microsoft Edge と共通で、「最新の3バージョン」 となります。

# 〇 最後に
以外とお手軽に Chromium っぽいブラウザを作れることがお分かりいただけたのではないでしょうか。
我こそはという方は、自分好みのブラウザを作っていただければと思います。

一方で、我々の提供する Microsoft Edge にこう言った機能が欲しい、というご意見もあるかと思います。
もし何かしらのご希望があれば、ぜひ下記よりフィードバックを頂ければ幸いです。もしかしたらご希望の機能が搭載される日が来るやもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48302/518a881a-9a8f-8d9a-f920-1a39f8f683fd.png)