Webview4DelphiでWebView2を使う ~Delphiでお手軽プログラミング

Webview4DelphiでWebView2を使う ~Delphiでお手軽プログラミング

WebView4Delphiは、ChromiumベースのEdgeをWebViewで使用できるコンポーネントです。
Delphi XE10.4以降はTEdgeBrowserがありますが、このコンポーネントを使うと、WebViewをDelphi XE4 以上で使用可能になるようです。(Delphi XE10.2 Tokyoで使えるのを確認しました。)

(1)Microsoft WebView2 ランタイムのインストール

(※Windows11は既にインストール済みなのでインストール不要)
https://developer.microsoft.com/ja-jp/microsoft-edge/webview2/
から[エバーグリーン ブートストラップ]の[ダウンロード]ボタンを押すと 「MicrosoftEdgeWebview2Setup.exe」ファイルがダウンロードできます。
ダウンロードした「MicrosoftEdgeWebview2Setup.exe」 ファイルをダブルクリックしてインストールします。

(2)WebView4Delphiのダウンロード

https://github.com/salvadordf/WebView4Delphi
から[Code]⇒[Download Zip]をクリックしてダウンロードします。
ダウンロードした「WebView4Delphi-main.zip」ファイルを解凍します。

(3)「WebView2Loader.dll」ファイルの準備

ダウンロードした「WebView4Delphi-main.zip」ファイルを解凍したフォルダ内に「WebView2Loader.dll」ファイルがあります。
32ビットアプリで、実行ファイルと同じフォルダ内に配置しなければならないファイル
WebView4Delphi-main\bin32\WebView2Loader.dll
64ビットアプリで、実行ファイルと同じフォルダ内に配置しなければならないファイル
WebView4Delphi-main\bin64\WebView2Loader.dll

(4)WebView2Delphiのインストール

(4)ー1.ライブラリパスの追加
Delphiを起動します。
[ツール]⇒[オプション]を開きます。
[言語]⇒[Delphi]⇒[ライブラリ]を選択します。
[ライブラリパス]の右にある「...」ボタンをクリックします。


[フォルダの参照]ボタンを押します。


「WebView4Delphi-main.zip」ファイルを解凍したフォルダ内の「source」フォルダを選択し、[フォルダーの選択]ボタンをクリックします。


[追加]ボタンを押して追加し、[OK]ボタンを押します。



選択したプラットフォームを[Windows 64 ビット]に切り替えて、同じように「ライブラリパス」に追加します。
追加したら[保存]ボタンを押します。

(4)ー2.コンポーネントのインストール
[ファイル]⇒[プロジェクトを開く]をクリックします。
解凍先フォルダの「\WebView4Delphi-main\packages\WebView4Delphi_group.groupproj」を選択して開きます。


右ペインの「webview4delphi_designtime.bpl」を右クリックして「インストール」をクリックします。

インストールが完了したので、[ファイル]⇒[すべて保存]を押し、[ファイル]⇒[すべて閉じる]を押して閉じます。

(3)プログラムの作成

(3)-①フォームの作成
Delphi IDEを起動し、「ファイル」⇒「Windows VCLアプリケーション -Delphi」をクリックします

フォームに、TPanelをドラッグ&ドロップし、プロパティ[align=alTop]に設定します。
Panel1にTEditを1つ、TButtonを5つドラッグ&ドロップします。
フォームにTMemoをドラッグ&ドロップし、プロパティ[align=alBottom]に設定します。
フォームにTWVBrowserをドラッグ&ドロップします。
フォームにTWVWindowParentをドラッグしてプロパティ[align=alClient]に設定します。

(3)-②ソースコードの記述
以下ソースコードを入力します
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  System.DateUtils,
  uWVWinControl, uWVWindowParent, uWVBrowserBase, uWVBrowser,
  uWVTypes, uWVConstants, uWVTypeLibrary, uWVLoader, uWVInterfaces,
  uWVCoreWebView2Args, uWVLibFunctions,
  uWVCoreWebView2CookieList, uWVCoreWebView2Cookie,
  uWVCoreWebView2HttpRequestHeaders,
  uWVCoreWebView2;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Edit1: TEdit;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    WVBrowser1: TWVBrowser;
    WVWindowParent1: TWVWindowParent;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure WVBrowser1AfterCreated(Sender: TObject);
    procedure WVBrowser1BasicAuthenticationRequested(Sender: TObject;
      const aWebView: ICoreWebView2;
      const aArgs: ICoreWebView2BasicAuthenticationRequestedEventArgs);
    procedure WVBrowser1DOMContentLoaded(Sender: TObject;
      const aWebView: ICoreWebView2;
      const aArgs: ICoreWebView2DOMContentLoadedEventArgs);
    procedure WVBrowser1GetCookiesCompleted(Sender: TObject; aResult: HRESULT;
      const aCookieList: ICoreWebView2CookieList);
    procedure WVBrowser1WebResourceRequested(Sender: TObject;
      const aWebView: ICoreWebView2;
      const aArgs: ICoreWebView2WebResourceRequestedEventArgs);
    procedure WVBrowser1NewWindowRequested(Sender: TObject;
      const aWebView: ICoreWebView2;
      const aArgs: ICoreWebView2NewWindowRequestedEventArgs);
    procedure Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  //戻るボタン
  if WVBrowser1.CanGoBack then WVBrowser1.GoBack;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  //進むボタン
  if WVBrowser1.CanGoForward then WVBrowser1.GoForward;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  //再読み込み
  WVBrowser1.Refresh;
end;

procedure TForm1.Button4Click(Sender: TObject);
var cookie:ICoreWebView2Cookie;
begin
  //クッキーを扱う

  //クッキーの全削除
  //WVBrowser1.DeleteAllCookies;

  //クッキーを追加または更新する場合
  cookie:=WVBrowser1.CreateCookie('name','value','mam-mam.net','/');

  //クッキーの有効期限設定
  cookie.Set_Expires(
    DateTimeToUnix(EncodeDateTime(2030,12,31,23,59,59,999),false)
  );
  cookie.Set_IsHttpOnly(-1);//HttpOnlyフラグ設定
  cookie.Set_IsSecure(-1);//Secureフラグ設定
  WVBrowser1.AddOrUpdateCookie(cookie);

  //クッキーの一覧を取得する
  //  ⇒WVBrowser1.OnGetCookiesCompletedイベントで取得
  WVBrowser1.GetCookies();
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  //指定URLを開く場合
  WVBrowser1.Navigate('https://mam-mam.net/');
end;

procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  //URLをキーボー入力してエンターキーを押した場合
  if Key = VK_RETURN then
  begin
    //入力されたURIを開く
    WVBrowser1.Navigate(Trim(Edit1.Text));
    Key := 0;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var ct:integer;
begin
 WVWindowParent1.Browser:=WVBrowser1;
 if GlobalWebView2Loader.InitializationError then
  begin
    ShowMessage(GlobalWebView2Loader.ErrorMessage);
  end
  else
  begin
    ct:=0;
    while (ct<20) and (not GlobalWebView2Loader.Initialized) do
    begin
      sleep(500);
      Application.ProcessMessages;
      inc(ct);
    end;
    if GlobalWebView2Loader.Initialized then
    begin
      WVBrowser1.CreateBrowser(WVWindowParent1.Handle);
      //参考:
      //ユーザーエージェントをWebView以外に変更するとGoogleログインも可能
      WVBrowser1.UserAgent:=
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'+
        ' AppleWebKit/537.36 (KHTML, like Gecko)'+
        ' Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53';
      //デフォルトのURLを設定
      Edit1.Text:='https://www.google.co.jp/';
      WVBrowser1.DefaultURL:=Edit1.Text;
    end
    else
    begin
      ShowMessage('WebView2初期化失敗');
    end;
  end;
end;

procedure TForm1.WVBrowser1AfterCreated(Sender: TObject);
begin
  //以下必須
  WVWindowParent1.UpdateSize;

  //カスタムヘッダーを送り込む場合
  //WVBrowser1.OnWebResourceRequestedイベントが発火するようになる
  WVBrowser1.AddWebResourceRequestedFilter(
    '*',COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL);
end;

procedure TForm1.WVBrowser1BasicAuthenticationRequested(Sender: TObject;
  const aWebView: ICoreWebView2;
  const aArgs: ICoreWebView2BasicAuthenticationRequestedEventArgs);
var r:ICoreWebView2BasicAuthenticationResponse;
    pwc:PChar;
begin
  //基本認証(ベーシック認証)の要求があった場合
  aWebView.Get_Source(pwc);
  if pwc='特定のURL' then
  begin
    aArgs.Get_Response(r);
    r.Set_UserName(PChar('基本認証ユーザー名'));
    r.Set_Password(PChar('基本認証パスワード'));
  end;
end;

procedure TForm1.WVBrowser1DOMContentLoaded(Sender: TObject;
  const aWebView: ICoreWebView2;
  const aArgs: ICoreWebView2DOMContentLoadedEventArgs);
var pUri:PChar;
begin
  //URLを移動した時にURLを表示する
  aWebView.Get_Source(pUri);
  Edit1.Text:=pUri;
end;

procedure TForm1.WVBrowser1GetCookiesCompleted(Sender: TObject;
  aResult: HRESULT; const aCookieList: ICoreWebView2CookieList);
var cookies:TCoreWebView2CookieList;
    cookie :TCoreWebView2Cookie;
    i:integer;
begin
  //クッキーの取得
  if assigned(aCookieList) then
  begin
    cookies:=TCoreWebView2CookieList.Create(aCookieList);
    cookie:=TCoreWebView2Cookie.Create(nil);
    try
      for i:=0 to cookies.Count-1 do
      begin
        cookie.BaseIntf:=cookies.Items[i];
        Memo1.Lines.Add(
          cookie.Domain+' '+cookie.Path+' '+
          //クッキー有効期限のUnixTimeをローカル時間に変換して表示する
          FormatDateTime('yyyy/mm/dd hh:nn:ss',UnixtoDateTime(trunc(cookie.Expires),false))+'  '+
          cookie.Name+'='+
          cookie.Value
        );
      end;
    finally
      FreeAndNil(cookie);
      freeandnil(cookies);
    end;
  end;
end;

procedure TForm1.WVBrowser1NewWindowRequested(Sender: TObject;
  const aWebView: ICoreWebView2;
  const aArgs: ICoreWebView2NewWindowRequestedEventArgs);
var pUri:PChar;
begin
  //<a target="_blank" rel="noreferrer">をクリックし、
  //新しいブラウザWindowを開こうとした場合
  //とりあえず、新しいブラウザウィンドウを開かせないようにキャンセルする
  aArgs.Set_Handled(-1);

  //キャンセルしない場合は別ウィンドウが開く
  //aArgs.Set_Handled(0);

  //新しいブラウザウィンドウの要求URLを取得する
  aArgs.Get_uri(pUri);
  showmessage(
    '新しいブラウザウィンドウを開こうとしました'+
    #13#10+pUri
  );
end;

procedure TForm1.WVBrowser1WebResourceRequested(Sender: TObject;
  const aWebView: ICoreWebView2;
  const aArgs: ICoreWebView2WebResourceRequestedEventArgs);
var rq:ICoreWebView2WebResourceRequest;
    rh:ICoreWebView2HttpRequestHeaders;
    pUri:PChar;
begin
  //常時カスタムヘッダーを送り込む場合
  aArgs.Get_Request(rq);
  rq.Get_Headers(rh);
  rh.SetHeader('X-Test-Always','username');

  //特定URIリクエスト時にカスタムヘッダーを送り込む場合
  aArgs.Get_Request(rq);
  rq.Get_uri(pUri);
  if pUri='https://hoge.hoge/' then
  begin
    rq.Get_Headers(rh);
    rh.SetHeader('X-Test','username');
  end;
end;

initialization
  // GlobalWebView2Loaderをロードして初期化
  GlobalWebView2Loader := TWVLoader.Create(nil);
  //キャッシュやクッキー等の保存場所を指定する
  GlobalWebView2Loader.UserDataFolder :=
    ExtractFilePath(Application.ExeName) + 'CustomCache';
  GlobalWebView2Loader.StartWebView2;

end.
(3)-③ユニットとプロジェクトの保存
「ファイル」⇒「すべて保存 Ctrl+Shift+S」をクリックして、ユニット(Unit1)とプロジェクト(Project1)を保存します

(3)-④プロジェクトのビルト
次に、「プロジェクト」⇒「Project1をビルト Shift+F9」をクリックします

(4)「WebView2Loader.dll」ファイルを実行ファイルと同じフォルダ内にコピーする

ダウンロードした「WebView4Delphi-main.zip」ファイルを解凍したフォルダ内に「bin32」と「bin64」フォルダがあり、その中に「WebView2Loader.dll」ファイルがあります。
「bin32\WebView2Loader.dll」
ファイルを、(3)-④でビルトした実行ファイルと同じフォルダ内(プロジェクト保存フォルダ\Win32\Debug)にコピーします
(A)「Debug」ビルトで
「Windows 32ビット」
プロジェクト保存フォルダ\Win32\Debug
(B)「Debug」ビルトで
「Windows 64ビット」
プロジェクト保存フォルダ\Win64\Debug
(C)「Release」ビルトで
「Windows 32ビット」
プロジェクト保存フォルダ\Win32\Release
(D)「Release」ビルトで
「Windows 64ビット」
プロジェクト保存フォルダ\Win64\Release

(5)実行する

「実行」⇒「実行」をクリックすると実行します
Button1をクリックすると、Webが表示されます

配布時について

配布時に必要なファイルは、