Вызов собственного кода из веб-кода
WebView2 позволяет приложениям преодолеть разрыв между веб-интерфейсом и собственной стороной приложения, позволяя передавать объект в Интернет. Вы предоставляете выбранные собственные API на веб-странице JavaScript через промежуточный собственный объект узла, определенный в машинном коде. Api на стороне машинного кода проецируются в JavaScript с помощью API WebView2 AddHostObjectToScript
.
В этой статье рассматриваются главным образом Win32/C++, а также некоторые аспекты .NET/C# в кадрах. Сведения о WinRT см. в статье Вызов собственного кода WinRT из веб-кода.
Зачем использовать AddHostObjectToScript
?
При разработке приложения WebView2 может возникнуть собственный объект, методы или свойства которого считаются полезными. Вы можете активировать эти собственные методы объектов из веб-кода в результате взаимодействия с пользователем на веб-стороне приложения. Кроме того, может не потребоваться повторно реализовывать методы собственных объектов в веб-коде. API
AddHostObjectToScript
позволяет повторно использовать собственный код с помощью веб-кода.Например, может быть собственный API веб-камеры, который потребует повторной записи большого объема кода на веб-стороне. Возможность вызова методов собственного объекта быстрее и эффективнее, чем повторное кодирование методов объекта на веб-стороне приложения. В этом случае собственный код может передать объект в веб-код JavaScript приложения, чтобы код JavaScript можно было повторно использовать методы собственного API.
Сценарии, которые могут извлечь выгоду из использования объектов узла в скрипте:
Существует API клавиатуры, и вы хотите вызвать функцию
keyboardObject.showKeyboard
с веб-стороны.Доступ к файловой системе, а не только к песочнице веб-страницы, через JavaScript. JavaScript является изолированным, что предотвращает прямой доступ к файловой системе. Используя для
AddHostObjectToScript
создания собственного объекта, доступного для JavaScript, вы можете использовать главный объект для управления файлами в файловой системе, а не только в песочнице веб-страницы.
В этой статье используется пример приложения Win32 для демонстрации некоторых практических применений AddHostObjectToScript
.
Шаг 1. Установка Visual Studio, установка Git, клонирование репозитория WebView2Samples и открытие решения
Скачайте и установите Microsoft Visual Studio 2019 (версии 16.11.10) или более поздней версии, а также другие предварительные требования, как описано в примере приложения Win32. Пример приложения Win32 был создан с помощью Visual Studio 2019, поэтому для выполнения примеров действий, описанных в этой статье, рекомендуется начать с Visual Studio 2019, а не с Visual Studio 2022.
Клонируйте репозиторий WebView2Samples . Репозиторий содержит пример приложения WebView2 для Win32. Инструкции в новом окне или на вкладке см. в разделе Пример приложения Win32.
Откройте Microsoft Visual Studio. Рекомендуется сначала открыть пример Win32 с помощью Visual Studio 2019.
В локальной копии клонированного
WebView2Samples
репозитория откройтеSampleApps
>WebView2Samples
>WebView2Samples.sln.WebView2Samples.sln
включает проектWebView2APISample
, который является примером приложения Win32. Не закрывайте пример решения для приложений, чтобы продолжить работу с остальной частью этой статьи.
Шаг 2. Определение COM-интерфейса объекта узла с помощью IDL
Определите COM-интерфейс объекта узла в .idl
файле, например HostObjectSample.idl, чтобы описать методы и свойства объекта узла.
Сначала используйте язык определения интерфейса (IDL) для определения COM-интерфейса объекта узла. Это определение объекта узла в idl
файле описывает предоставляемые (или "упакованные") собственные свойства и методы. IDL-файл (.idl
) определяет интерфейс, но не реализует его.
В обозревателе решений Visual Studio разверните узел WebView2APISample>Source Files, а затем дважды щелкните
HostObjectSample.idl
, чтобы открыть его.Следующий код определяет
IHostObjectSample
интерфейс, который наследуетIUnknown
в соответствии со стандартом 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(); };
Выше обратите внимание на
DateProperty
, в котором используетсяDATE
тип . В этой статье мы сосредоточимся на этом демонстрационном свойстве date.
Шаг 3. Определение совместного класса объекта узла
Далее в примере определяется HostObjectSample
класс для включения IHostObjectSample
и IDispatch
.
В
HostObjectSample.idl
изучитеHostObjectSample
класс ( класс объектов компонента), который включаетIHostObjectSample
интерфейсы иIDispatch
:[uuid(637abc45-11f7-4dde-84b4-317d62a638d3)] coclass HostObjectSample { [default] interface IHostObjectSample; interface IDispatch; }; }
Coclass
HostObjectSample
включает в себяinterface IDispatch
, который необходим для работы ведущего объекта сAddHostObjectToScript
.
Шаг 4. Реализация членов объекта C++
В примере кода приложения Win32 HostObjectSampleImpl.cpp берет скелет, созданный в ФАЙЛЕ COM IDL, и реализует каждый член объекта C++. Этот файл C++ (.cpp
) реализует определенный интерфейс (и также реализует IDispatch
).
Реализуйте все функции, определенные в интерфейсе объекта, как описано в IDL-файле. Обязательно реализуйте функции, необходимые для IDispatch
. Компилятор выдает ошибку, если эти функции не определены.
Далее мы рассмотрим два конкретных свойства, которые были определены в IDL, чтобы показать, как 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
Объект узла должен реализовать IDispatch
, чтобы WebView2 могла проецировать собственный объект узла в веб-код приложения.
IDispatch
позволяет динамически вызывать методы и свойства. Как правило, для вызова объектов требуются статические вызовы, но для динамического создания вызовов объектов можно использовать JavaScript. В примере кода приложения Win32 HostObjectSampleImpl.cpp реализует IDispatch
, что означает реализацию следующих методов:
GetIDsOfNames
GetTypeInfo
GetTypeInfoCount
Invoke
Реализуйте IDispatch
, как описано в разделах Библиотеки типов и язык описания объектов. Дополнительные сведения о IDispatch
наследовании и методах см. в разделе Интерфейс IDispatch (oaidl.h).
Если объект, который требуется добавить в JavaScript, еще не реализует IDispatch
, необходимо написать оболочку IDispatch
класса для объекта, который требуется предоставить.
Для автоматического выполнения этой действия могут быть библиотеки. Дополнительные сведения о шагах, необходимых для написания IDispatch
оболочки класса для объекта, который требуется предоставить, см. в разделе Автоматизация.
Затем сохраните все изменения, внесенные в проект.
В обозревателе решений щелкните правой кнопкой мыши webView2APISample (пример приложения Win32), а затем выберите Сборка. При этом создается файл библиотеки
.tlb
типов COM. Необходимо ссылаться на.tlb
файл из исходного кода C++. Дополнительные сведения см. в статье Библиотека типов в com, DCOM и библиотеках типов.
Шаг 6. Вызов метода AddHostObjectToScript для передачи объекта узла в веб-код
На данный момент мы создали наш интерфейс и реализовали собственный объект узла. Теперь мы готовы использовать AddHostObjectToScript
для передачи собственного объекта узла в код JavaScript веб-приложения. Пример приложения Win32 вызывает AddHostObjectToScript
в ScenarioAddHostObject.cpp, как показано ниже.
В обозревателе решений 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
показывает, как создать экземплярHostObjectSample
COM-объекта, определенного в IDL-файле. Это объект, который мы будем использовать позже при вызове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
событий строка (ниже) приводит только что созданный com-объект к типуIDispatch
,query_to
а затем преобразует объект в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++, собственный код примера приложения готов к передаче ведущего объекта в веб-код приложения.
В нижней строке
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
VARIANT
событий передаетсяAddHostObjectToScript
в , используя имяsample
.
Шаг 7. Доступ к элементам объекта узла с веб-страницы JavaScript
На описанных выше шагах собственный код примера приложения создал объект узла, который реализует IDispatch
. Этот машинный код также вызывает API ICoreWebView2::AddHostObjectToScript
WebView2 или ICoreWebView2Frame::AddHostObjectToScriptWithOrigins
и передает объект узла в веб-код приложения.
Теперь веб-код приложения может обращаться к собственным API, которые предоставляются объектом узла. Инструкции JavaScript в .html
элементе веб-страницы script
или в файле JavaScript, на который ссылается .js
ссылка, могут обращаться к экспортированным API на стороне собственного кода.
Веб-код примера приложения Win32 теперь может получить доступ к свойствам и методам собственного объекта узла для доступа к собственным API. Для демонстрации этого мы будем использовать элементы управления веб-страницы примера приложения на веб-страницеобъектов размещениясценариев> приложения.
В Microsoft Visual Studio выберите Файл>Сохранить все (CTRL+SHIFT+S), чтобы сохранить проект.
В обозревателе решений откройте WebView2APISample>ScenarioAddHostObject.html. Мы сравним этот файл с соответствующей веб-страницей в работающем примере приложения Win32.
В обозревателе решений щелкните правой кнопкой мыши webView2APISample (пример приложения Win32), а затем выберите Сборка.
Нажмите клавишу F5 , чтобы запустить проект в режиме отладки.
В примере приложения Win32 (в строке заголовка WebView2APISample) щелкните меню Сценарий , а затем выберите пункт Меню Объекты узла . Откроется пример веб-страницы AddHostObjectToScript , определяемой параметром
ScenarioAddHostObject.html
:На веб-странице предлагается использовать консоль средства DevTools для запуска операторов JavaScript для
chrome.webview.hostObjects.sample
объекта . Если вы хотите открыть DevTools из примера приложения, щелкните страницу правой кнопкой мыши и выберите пункт Проверить. Затем перейдите на вкладку Консоль . Дополнительные сведения см. в разделе Общие сведения о консоли.Чтобы открыть средства разработки, нажатие клавиши F12 может не работать в этом контексте и вызвать исключение. Если это так, в Visual Studio выберите Остановить отладку и нажмите клавишу F5 , чтобы перезапустить отладку. В примере приложения снова выберите Объекты размещения сценариев>. Дополнительные сведения см. в статье Открытие средств разработки с помощью подхода, отличного от F12 , в статье Отладка приложений WebView2 с помощью Visual Studio.
В нижней части демонстрационной страницы "Объекты узла" дублируются члены демонстрационного объекта в :
<iframe>
На отображаемой демонстрационной странице в примере приложения прочитайте текст метки, объясняющий кнопки Даты .
Нажмите кнопки Дата . Под кнопками отображается строка даты, например:
sample.dateProperty: Tue Nov 01 2022 12:45:25 GMT-0700 (Pacific Daylight Time)
Изучите свойства и методы, нажав кнопки на демонстрационной веб-странице и введя значения, чтобы узнать, как работает пример кода. Кнопки демонстрируют доступ к свойствам и методам ведущего объекта из веб-кода приложения.
Чтобы получить представление о том, что происходит в JavaScript, изучите следующий код в ScenarioAddHostObject.html.
Следующий код представляет собой демонстрационное
Date
свойство непосредственно в элементеbody
:<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>
Вы также можете прочитать приведенный выше текст метки на отображаемой демонстрационной странице в примере приложения, объяснив код кнопки Дата .
Следующий код представляет собой демонстрационное
Date
свойство, которое упаковывается вiframe
элемент, созданный в элементеscript
:// 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 определяется как часть объекта host.
Использование примера приложения
Вы можете поэкспериментировать с использованием и изменением примера приложения Win32. Затем следуйте тому же шаблону в собственном приложении:
- Создайте объект узла в собственном коде приложения.
- Передайте объект узла в веб-код приложения.
- Используйте объект host из веб-кода приложения.
Сведения о других API-интерфейсах, которые существуют в экосистеме объектов узла, см. в статье WebView2 Win32 C++ ICoreWebView2.
Обзор справочника по API
См. раздел Общий доступ к объектам узла и веб-сайта в обзоре функций и API WebView2.
См. также
- Веб-взаимодействие с собственными возможностями в обзоре функций и API WebView2.
- Использование кадров в приложениях WebView2
- Вызов собственного кода WinRT из веб-кода
GitHub: