Web 側コードからネイティブ側コードを呼び出す
WebView2 を使用すると、オブジェクトを Web に渡すことにより、アプリケーションがアプリケーションの Web 側とネイティブ側の間のギャップを埋められます。 ネイティブ コードで定義されている中間ネイティブ ホスト オブジェクトを使用して、選択したネイティブ側 API を Web ページ JavaScript に公開します。 ネイティブ側 API は、WebView2 AddHostObjectToScript
API を使用して JavaScript に投影されます。
この記事では主に Win32/C++ について説明し、フレーム内の .NET/C# のいくつかの側面についても説明します。 WinRT については、「 Web 側コードからネイティブ側の WinRT コードを呼び出す」を参照してください。
AddHostObjectToScript
を使用する理由
WebView2 アプリを開発するときに、メソッドまたはプロパティが役に立つネイティブ オブジェクトが見つかる場合があります。 アプリの Web 側でのユーザー操作の結果として、Web 側のコードからこれらのネイティブ オブジェクト メソッドをトリガーする必要がある場合があります。 さらに、Web 側コードでネイティブ オブジェクトのメソッドを再実装したくない場合もあります。
AddHostObjectToScript
API を使用すると、Web 側コードによるネイティブ側コードの再利用が可能になります。たとえば、Web 側で大量のコードを書き直す必要があるネイティブ Web カメラ API が存在する場合があります。 ネイティブ オブジェクトのメソッドを呼び出す機能を持つことは、アプリの Web 側でオブジェクトのメソッドを再コーディングするよりも迅速かつ効率的です。 この場合、ネイティブ側のコードは、JavaScript コードがネイティブ API のメソッドを再利用できるように、アプリの Web 側の JavaScript コードにオブジェクトを渡すことができます。
スクリプトでホスト オブジェクトを使用する利点があるシナリオ:
キーボード API があり、web 側から
keyboardObject.showKeyboard
関数を呼び出す必要があります。JavaScript を使用して、Web ページのサンドボックスだけでなく、ファイル システムにアクセスする。 JavaScript はサンドボックス化されているため、ファイル システムに直接アクセスできなくなります。
AddHostObjectToScript
を使用して JavaScript に公開されるネイティブ オブジェクトを作成すると、ホスト オブジェクトを使用して、Web ページ サンドボックスだけでなく、ファイル システム上のファイルを操作できます。
この記事では、 Win32 サンプル アプリ を使用して、 AddHostObjectToScript
のいくつかの実用的なアプリケーションを示します。
手順 1: Visual Studio をインストールし、git をインストールし、WebView2Samples リポジトリを複製して、ソリューションを開く
Win32 サンプル アプリで説明されているように、Microsoft Visual Studio 2019 (バージョン 16.11.10) 以降とその他の前提条件をダウンロードしてインストールします。 Win32 サンプル アプリは Visual Studio 2019 を使用して作成されているため、この記事の例の手順に従うために、Visual Studio 2022 ではなく Visual Studio 2019 から開始することをお勧めします。
WebView2Samples リポジトリを複製します。 リポジトリには、Win32 固有の WebView2 サンプル アプリが含まれています。 手順については、新しいウィンドウまたはタブで、「 Win32 サンプル アプリ」を参照してください。
Microsoft Visual Studio を起動します。 最初に Visual Studio 2019 を使用して Win32 サンプルを開くお勧めします。
複製された
WebView2Samples
リポジトリのローカル コピーで、WebView2Samples
>SampleApps
>WebView2Samples.slnを開きます。WebView2Samples.sln
には、Win32 サンプル アプリであるWebView2APISample
プロジェクトが含まれています。 サンプル アプリ ソリューションを開いたままにして、この記事の残りの部分に従ってください。
手順 2: IDL を使用してホスト オブジェクトの COM インターフェイスを定義する
HostObjectSample.idl などの.idl
ファイルでホスト オブジェクトの COM インターフェイスを定義して、ホスト オブジェクトのメソッドとプロパティを記述します。
まず、インターフェイス定義言語 (IDL) を使用して、ホスト オブジェクトの COM インターフェイスを定義します。
idl
ファイル内のこのホスト オブジェクト定義は、公開されている (または "ラップされた") ネイティブ側のプロパティとメソッドについて説明します。 IDL (.idl
) ファイルはインターフェイスを 定義 しますが、実装していません。
Visual Studio ソリューション エクスプローラーで、 WebView2APISample>Source Files を展開し、
HostObjectSample.idl
ダブルクリックして開きます。次のコードでは、 インターフェイスを定義します。このインターフェイスは、COM の標準としてを継承します。 この
IHostObjectSample
定義は、オブジェクトのメソッド、プロパティ、コールバック関数などを定義するためのテンプレートとして使用します。import "oaidl.idl"; import "ocidl.idl"; [uuid(0a7a4655-5660-47d0-8a37-98ae21399e57), version(0.1)] library HostObjectSampleLibrary { [uuid(3a14c9c0-bc3e-453f-a314-4ce4a0ec81d8), object, local] interface IHostObjectSample : IUnknown { // Demonstrates a basic method call with some parameters and a return value. HRESULT MethodWithParametersAndReturnValue([in] BSTR stringParameter, [in] INT integerParameter, [out, retval] BSTR* stringResult); // Demonstrate getting and setting a property. [propget] HRESULT Property([out, retval] BSTR* stringResult); [propput] HRESULT Property([in] BSTR stringValue); [propget] HRESULT IndexedProperty(INT index, [out, retval] BSTR * stringResult); [propput] HRESULT IndexedProperty(INT index, [in] BSTR stringValue); // Demonstrate native calling back into JavaScript. HRESULT CallCallbackAsynchronously([in] IDispatch* callbackParameter); // Demonstrates a property which uses Date types. [propget] HRESULT DateProperty([out, retval] DATE * dateResult); [propput] HRESULT DateProperty([in] DATE dateValue); // Creates a date object on the native side and sets the DateProperty to it. HRESULT CreateNativeDate(); };
上記では、
DATE
型を使用するDateProperty
に注意してください。 この記事では、この日付デモ プロパティに焦点を当てます。
手順 3: ホスト オブジェクトのコクラスを定義する
次に、この例では、IHostObjectSample
とIDispatch
を含めるHostObjectSample
コクラスを定義します。
HostObjectSample.idl
で、IHostObjectSample
インターフェイスとIDispatch
インターフェイスを含むHostObjectSample
coclass (コンポーネント オブジェクト クラス) を調べます。[uuid(637abc45-11f7-4dde-84b4-317d62a638d3)] coclass HostObjectSample { [default] interface IHostObjectSample; interface IDispatch; }; }
HostObjectSample
コクラスには、ホスト オブジェクトがAddHostObjectToScript
で動作するために必要なinterface IDispatch
が含まれています。
手順 4: C++ オブジェクトのメンバーを実装する
Win32 サンプル アプリ コードでは、 HostObjectSampleImpl.cpp COM IDL ファイルで作成されたスケルトンを受け取り、C++ オブジェクトの各メンバーを実装します。 この C++ (.cpp
) ファイルは、定義されたインターフェイスを 実装 します (また、 IDispatch
も実装します)。
IDL ファイルで説明したように、オブジェクトのインターフェイスで定義されているすべての関数を実装します。 必ず、 IDispatch
で必要な関数を実装してください。 これらの関数が定義されていない場合、コンパイラはエラーをスローします。
次に、IDL で定義された 2 つの特定のプロパティを調べて、IDL が .cpp
ファイルにどのように関連しているかを示します。
Visual Studio ソリューション エクスプローラーで、[ WebView2APISample>Source Files] を展開し、 HostObjectSampleImpl.cpp ダブルクリックして開きます。
HostObjectSample.idl のプロパティ宣言を調べます。
// Demonstrate getting and setting a property. [propget] HRESULT Property([out, retval] BSTR* stringResult); [propput] HRESULT Property([in] BSTR stringValue); ... // Demonstrate a property which uses Date types [propget] HRESULT DateProperty([out, retval] DATE * dateResult); [propput] HRESULT DateProperty([in] DATE dateValue); // Creates a date object on the native side and sets the DateProperty to it. HRESULT CreateNativeDate();
HostObjectSampleImpl.cppでのオブジェクトのプロパティの実装を調べます。
STDMETHODIMP HostObjectSample::get_Property(BSTR* stringResult) { *stringResult = SysAllocString(m_propertyValue.c_str()); return S_OK; } STDMETHODIMP HostObjectSample::put_Property(BSTR stringValue) { m_propertyValue = stringValue; return S_OK; } ... STDMETHODIMP HostObjectSample::get_DateProperty(DATE* dateResult) { *dateResult = m_date; return S_OK; } STDMETHODIMP HostObjectSample::put_DateProperty(DATE dateValue) { m_date = dateValue; SYSTEMTIME systemTime; if (VariantTimeToSystemTime(dateValue, &systemTime)) ... } STDMETHODIMP HostObjectSample::CreateNativeDate() { SYSTEMTIME systemTime; GetSystemTime(&systemTime); DATE date; if (SystemTimeToVariantTime(&systemTime, &date)) { return put_DateProperty(date); } return E_UNEXPECTED; }
この記事全体を通じてトレースする
DateProperty
を調べます。
手順 5: IDispatch を実装する
WebView2 がネイティブ ホスト オブジェクトをアプリの Web 側コードに投影できるように、ホスト オブジェクトは IDispatch
を実装する必要があります。
IDispatch
では、メソッドとプロパティを動的に呼び出すことができます。 通常、オブジェクトを呼び出すには静的呼び出しが必要ですが、JavaScript を使用してオブジェクト呼び出しを動的に作成できます。 Win32 サンプル アプリ コードでは、 HostObjectSampleImpl.cpp は IDispatch
を実装します。つまり、次のメソッドを実装します。
GetIDsOfNames
GetTypeInfo
GetTypeInfoCount
Invoke
「タイプ ライブラリとオブジェクト記述言語」の説明に従って、IDispatch
を実装します。
IDispatch
の継承とメソッドの詳細については、「IDispatch インターフェイス (oaidl.h)」を参照してください。
JavaScript に追加するオブジェクトに IDispatch
がまだ実装されていない場合は、公開するオブジェクトの IDispatch
クラス ラッパーを記述する必要があります。
これを自動的に実行するライブラリが存在する可能性があります。 公開するオブジェクトの IDispatch
クラス ラッパーを記述するために必要な手順の詳細については、「 Automation」を参照してください。
次に、プロジェクトで行った変更を保存します。
ソリューション エクスプローラーで、 WebView2APISample (Win32 サンプル アプリ) を右クリックし、[ ビルド] を選択します。 これにより、ファイル
.tlb
COM タイプ ライブラリが作成されます。 C++ ソース コードから.tlb
ファイルを参照する必要があります。 詳細については、「COM、DCOM、およびタイプライブラリのタイプ ライブラリ」を参照してください。
手順 6: AddHostObjectToScript を呼び出して、ホスト オブジェクトを Web 側のコードに渡す
ここまでは、インターフェイスを構築し、ネイティブ ホスト オブジェクトを実装しました。 これで、 AddHostObjectToScript
を使用して、ネイティブ ホスト オブジェクトをアプリの Web 側の JavaScript コードに渡す準備ができました。 Win32 サンプル アプリは、次に示すように、ScenarioAddHostObject.cppでAddHostObjectToScript
を呼び出します。
Visual Studio ソリューション エクスプローラーで、 WebView2APISample>Source Files>ScenarioAddHostObject.cpp を開きます。
ScenarioAddHostObject
クラスの実装に移動します。 このクラスは HTML を表示し、ナビゲーションを処理します。ScenarioAddHostObject::ScenarioAddHostObject(AppWindow* appWindow) : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) { std::wstring sampleUri = m_appWindow->GetLocalUri(L"ScenarioAddHostObject.html"); m_hostObject = Microsoft::WRL::Make<HostObjectSample>( [appWindow = m_appWindow](std::function<void(void)> callback) { appWindow->RunAsync(callback); });
Make
ステートメントは、IDL ファイルで定義されたHostObjectSample
COM オブジェクトをインスタンス化する方法を示しています。 これは、後でAddHostObjectToScript
を呼び出すときに使用するオブジェクトです。Make
ステートメントは、HostObjectSampleImpl.cppで実装されているインターフェイスへのポインターを取得します。次に、
NavigationStarting
イベントをリッスンするイベント ハンドラーを追加します。CHECK_FAILURE(m_webView->add_NavigationStarting( Microsoft::WRL::Callback<ICoreWebView2NavigationStartingEventHandler>( [this, sampleUri](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT { wil::unique_cotaskmem_string navigationTargetUri; CHECK_FAILURE(args->get_Uri(&navigationTargetUri)); std::wstring uriTarget(navigationTargetUri.get());
NavigationStarting
イベント ハンドラーでは、query_to
行 (下) によって、新しく作成された COM オブジェクトがIDispatch
型にキャストされ、オブジェクトがVARIANT
に変換されます。VARIANT
型を使用すると、整数や配列などのデータ構造だけでなく、IDispatch
などのより複雑な型を使用できます。サポートされているデータ型の完全な一覧については、「 VARIANT 構造体 (oaidl.h)」を参照してください。
VARIANT
共用体のすべての型がAddHostObjectToScript
でサポートされているわけではありません。 詳細については、「 ICoreWebView2::AddHostObjectToScript メソッド」を参照してください。if (AreFileUrisEqual(sampleUri, uriTarget)) { VARIANT remoteObjectAsVariant = {}; m_hostObject.query_to<IDispatch>(&remoteObjectAsVariant.pdispVal); remoteObjectAsVariant.vt = VT_DISPATCH;
C++ コードフレンドリなオブジェクトのバリアントが作成されたので、サンプル アプリのネイティブ側コードで、ホスト オブジェクトをアプリの Web 側コードに渡す準備ができました。
上の一番下の行では、
NavigationStarting
イベント ハンドラーによってリモート オブジェクトのバリアント型がIDispatch
として設定されます。// We can call AddHostObjectToScript multiple times in a row without // calling RemoveHostObject first. This will replace the previous object // with the new object. In our case this is the same object and everything // is fine. CHECK_FAILURE( m_webView->AddHostObjectToScript(L"sample", &remoteObjectAsVariant)); remoteObjectAsVariant.pdispVal->Release(); }
上記の
NavigationStarting
イベント ハンドラーでは、sample
という名前を使用して、VARIANT
がAddHostObjectToScript
に渡されます。
手順 7: Web ページ JavaScript からホスト オブジェクト メンバーにアクセスする
上記の手順では、サンプル アプリのネイティブ側コードによって、 IDispatch
を実装するホスト オブジェクトが作成されました。 このネイティブ コードは、WebView2 API ICoreWebView2::AddHostObjectToScript
または ICoreWebView2Frame::AddHostObjectToScriptWithOrigins
も呼び出し、ホスト オブジェクトをアプリの Web 側コードに渡します。
これで、アプリの Web 側コードが、ホスト オブジェクトによって公開されるネイティブ側 API にアクセスできるようになりました。
.html
Web ページscript
要素内の JavaScript ステートメント、または参照.js
JavaScript ファイル内の JavaScript ステートメントは、エクスポートされたネイティブ側 API にアクセスできます。
Win32 サンプル アプリの Web 側コードは、ネイティブ ホスト オブジェクトのプロパティとメソッドにアクセスして、ネイティブ API にアクセスできるようになりました。 サンプル アプリの Web ページ コントロールを使用して、アプリの Scenario>Host Objects Web ページでこれを示します。
Microsoft Visual Studio で、[ファイル] >[すべて保存] (Ctrl + Shift + S) を選択してプロジェクトを保存します。
ソリューション エクスプローラーで、 WebView2APISample>ScenarioAddHostObject.htmlを開きます。 このファイルを、実行中の Win32 サンプル アプリの対応する Web ページと比較します。
ソリューション エクスプローラーで、 WebView2APISample (Win32 サンプル アプリ) を右クリックし、[ ビルド] を選択します。
F5 キーを押して、プロジェクトをデバッグ モードで実行します。
Win32 サンプル アプリ ( WebView2APISample のタイトル バーがある) で、[ シナリオ ] メニューをクリックし、[ ホスト オブジェクト ] メニュー項目を選択します。
ScenarioAddHostObject.html
によって定義された AddHostObjectToScript サンプル Web ページが表示されます。Web ページでは、DevTools の コンソール ツールを使用して、
chrome.webview.hostObjects.sample
オブジェクトで JavaScript ステートメントを実行することを提案しています。 サンプル アプリから DevTools を開く場合は、ページを右クリックし、[ 検査] を選択します。 次に、[ コンソール ] タブを選択します。詳細については、「コンソールの 概要」を参照してください。DevTools を開くには、 F12 キーを押してもこのコンテキストでは機能せず、例外がトリガーされる可能性があります。 その場合は、Visual Studio で [ デバッグの停止] を選択し、 F5 キーを押してデバッグを再開します。 サンプル アプリで、もう一度 [ シナリオ>ホスト オブジェクト] を選択します。 詳細については、「Visual Studio で WebView2 アプリをデバッグする」で F12 以外の方法を使用して DevTools を開く方法に関するページを参照してください。
[ホスト オブジェクト] デモ ページの下部には、
<iframe>
内のデモ オブジェクト メンバーが複製されています。サンプル アプリのレンダリングされたデモ ページで、[ 日付] ボタンを説明するラベル テキストを読み取ります。
[ 日付 ] ボタンをクリックします。 日付文字列は、次のようなボタンの下に表示されます。
sample.dateProperty: Tue Nov 01 2022 12:45:25 GMT-0700 (Pacific Daylight Time)
デモ Web ページのボタンをクリックし、値を入力してプロパティとメソッドを調べて、サンプル コードの動作を確認します。 ボタンは、アプリの Web 側コードからホスト オブジェクトのプロパティとメソッドにアクセスする方法を示しています。
JavaScript で何が起こっているのかを把握するには、ScenarioAddHostObject.htmlで次のコード を 調べます。
次のコードは、
body
要素内の直接のデモDate
プロパティです。<h2>Date Objects</h2> <button id="setDateButton">Set Date to Now</button> <label for="setDateButton">Sets <code>chrome.webview.hostObjects.options.shouldSerializeDates = true</code> and then runs <code>chrome.webview.hostObjects.sample.dateProperty = new Date()</code></label> <br /> <button id="createRemoteDateButton">Set Remote Date</button> <label for="createRemoteDateButton">Calls <code>chrome.webview.hostObjects.sample.createNativeDate()</code> to have the native object create and set the current time to the DateProperty</label> <code><pre><span id="dateOutput"></span></pre></code> <div id="div_iframe" style="display: none;"> <h2>IFrame</h2> </div>
また、サンプル アプリのレンダリングされたデモ ページで上記のラベル テキストを読み上げ、 日付 ボタン コードについて説明することもできます。
次のコードは、
script
要素内に作成されたiframe
要素にラップされるデモDate
プロパティです。// Date property document.getElementById("setDateButton").addEventListener("click", () => { chrome.webview.hostObjects.options.shouldSerializeDates = true; chrome.webview.hostObjects.sync.sample.dateProperty = new Date(); document.getElementById("dateOutput").textContent = "sample.dateProperty: " + chrome.webview.hostObjects.sync.sample.dateProperty; }); document.getElementById("createRemoteDateButton").addEventListener("click", () => { chrome.webview.hostObjects.sync.sample.createNativeDate(); document.getElementById("dateOutput").textContent = "sample.dateProperty: " + chrome.webview.hostObjects.sync.sample.dateProperty; });
式
chrome.webview.hostObjects.sync.sample.dateProperty
は、ネイティブ ホスト オブジェクトのdateProperty
です。前に説明した
.idl
ファイル HostObjectSample.idl では、date プロパティはホスト オブジェクトの一部として定義されています。
サンプル アプリの使用
Win32 サンプル アプリの使用と変更を試すことができます。 次に、独自のアプリで同じパターンに従います。
- アプリのネイティブ側コードでホスト オブジェクトを作成します。
- ホスト オブジェクトをアプリの Web 側コードに渡します。
- アプリの Web 側コードからホスト オブジェクトを使用します。
ホスト オブジェクト エコシステムに含まれる他の API については、「 WebView2 Win32 C++ ICoreWebView2」を参照してください。
API リファレンスの概要
「WebView2 の機能と API の概要」の「ホスト/Web オブジェクトの共有」を参照してください。
関連項目
- WebView2 の機能と API の概要に関するページの Web/ネイティブ相互運用。
- WebView2 アプリでのフレームの使用
- Web 側コードからネイティブ側の WinRT コードを呼び出す
GitHub: