Llamada a código de lado nativo desde código del lado web
WebView2 permite a las aplicaciones cerrar la brecha entre los lados web y nativo de una aplicación al permitir que un objeto se pase a la web. Las API de lado nativo seleccionadas se exponen a la página web de JavaScript a través de un objeto host nativo intermedio definido en el código nativo. Las API de lado nativo se proyectan en JavaScript mediante la API WebView2 AddHostObjectToScript
.
En este artículo se trata principalmente Win32/C++, y también se tratan algunos aspectos de .NET/C# dentro de los marcos. Para WinRT, consulte Llamada al código winRT del lado nativo desde el código del lado web.
¿Por qué usar AddHostObjectToScript
?
Al desarrollar una aplicación WebView2, es posible que encuentre un objeto nativo cuyos métodos o propiedades le resultan útiles. Es posible que quiera desencadenar estos métodos de objetos nativos desde el código del lado web, como resultado de la interacción del usuario en el lado web de la aplicación. Además, es posible que no quiera volver a implementar los métodos de los objetos nativos en el código del lado web. La
AddHostObjectToScript
API permite volver a usar código nativo por código del lado web.Por ejemplo, podría haber una API nativa de cámara web, que requeriría volver a escribir una gran cantidad de código en la web. Tener la capacidad de llamar a los métodos del objeto nativo es más rápido y eficaz que volver a codificar los métodos del objeto en la web de la aplicación. En este caso, el código nativo puede pasar el objeto al código JavaScript del lado web de la aplicación para que el código JavaScript pueda reutilizar los métodos de la API nativa.
Escenarios que pueden beneficiarse del uso de objetos host en el script:
Hay una API de teclado y quiere llamar a la
keyboardObject.showKeyboard
función desde el lado web.Acceso al sistema de archivos, no solo al espacio aislado de la página web, a través de JavaScript. JavaScript está en espacio aislado, lo que impide que acceda directamente al sistema de archivos. Mediante el uso
AddHostObjectToScript
de para crear un objeto nativo que se expone a JavaScript, puede usar el objeto host para manipular archivos en el sistema de archivos, no solo en el espacio aislado de la página web.
En este artículo se usa la aplicación de ejemplo Win32 para mostrar algunas aplicaciones prácticas de AddHostObjectToScript
.
Paso 1: Instalar Visual Studio, instalar Git, clonar el repositorio WebView2Samples y abrir la solución
Descargue e instale Microsoft Visual Studio 2019 (versión 16.11.10) o posterior, y otros requisitos previos como se describe en Aplicación de ejemplo win32. La aplicación de ejemplo Win32 se creó con Visual Studio 2019, por lo que para seguir los pasos de ejemplo de este artículo, se recomienda empezar por Visual Studio 2019 en lugar de Visual Studio 2022.
Clone el repositorio WebView2Samples . El repositorio incluye la aplicación de ejemplo WebView2 específica de Win32. Para obtener instrucciones, en una nueva ventana o pestaña, consulte Aplicación de ejemplo win32.
Abra Microsoft Visual Studio. Se recomienda abrir inicialmente el ejemplo win32 mediante Visual Studio 2019.
En la copia local del repositorio clonado
WebView2Samples
, abraSampleApps
>WebView2Samples
>WebView2Samples.sln.WebView2Samples.sln
incluye elWebView2APISample
proyecto, que es la aplicación de ejemplo win32. Mantenga abierta la solución de aplicación de ejemplo para seguir el resto de este artículo.
Paso 2: Definir la interfaz COM del objeto host mediante IDL
Defina la interfaz COM del objeto host en un .idl
archivo, como HostObjectSample.idl, para describir los métodos y las propiedades del objeto host.
En primer lugar, use el lenguaje de definición de interfaz (IDL) para definir la interfaz COM del objeto host. Esta definición de objeto host en un idl
archivo describe las propiedades y métodos del lado nativo expuestos (o "encapsulados"). El archivo IDL (.idl
) define una interfaz, pero no la implementa.
En el Explorador de soluciones de Visual Studio, expanda WebView2APISample>Source Files y, a continuación, haga doble clic
HostObjectSample.idl
para abrirlo.El código siguiente define la
IHostObjectSample
interfaz, que heredaIUnknown
como estándar para COM. Use estaIHostObjectSample
definición como plantilla para definir los métodos, las propiedades, las funciones de devolución de llamada del objeto, etc.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(); };
Anteriormente, tenga en cuenta ,
DateProperty
que usa unDATE
tipo . Nos centraremos en esta propiedad de demostración de fecha en este artículo.
Paso 3: Definir una coclase de objetos host
A continuación, en el ejemplo se define la HostObjectSample
coclase que se va a incluir IHostObjectSample
y IDispatch
.
En
HostObjectSample.idl
, examine laHostObjectSample
coclase (clase de objeto de componente), que incluye lasIHostObjectSample
interfaces yIDispatch
:[uuid(637abc45-11f7-4dde-84b4-317d62a638d3)] coclass HostObjectSample { [default] interface IHostObjectSample; interface IDispatch; }; }
La
HostObjectSample
coclase incluyeinterface IDispatch
, que es necesario para que el objeto host funcione conAddHostObjectToScript
.
Paso 4: Implementar los miembros del objeto de C++
En el código de aplicación de ejemplo de Win32, HostObjectSampleImpl.cpp toma el esqueleto que se crea en el archivo IDL COM e implementa cada miembro del objeto de C++. Este archivo de C++ (.cpp
) implementa la interfaz definida (y también implementa IDispatch
).
Implemente todas las funciones definidas en la interfaz del objeto, como se describe en el archivo IDL. Asegúrese de implementar las funciones necesarias para IDispatch
. El compilador producirá un error si estas funciones no están definidas.
A continuación, examinamos dos propiedades específicas que se definieron en el IDL para mostrar cómo está relacionado el IDL con el .cpp
archivo.
En el Explorador de soluciones de Visual Studio, expanda WebView2APISample>Source Files y, a continuación, haga doble clic en HostObjectSampleImpl.cpp para abrirlo.
Examine las declaraciones de propiedad en 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();
Examine la implementación de las propiedades del objeto en 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; }
Examine
DateProperty
, que rastreamos a lo largo de este artículo.
Paso 5: Implementar IDispatch
El objeto host debe implementarse IDispatch
para que WebView2 pueda proyectar el objeto host nativo en el código del lado web de la aplicación.
IDispatch
permite invocar dinámicamente métodos y propiedades. Normalmente, la llamada a objetos requiere invocaciones estáticas, pero puede usar JavaScript para crear dinámicamente llamadas a objetos. En el código de aplicación de ejemplo de Win32, HostObjectSampleImpl.cpp implementa IDispatch
, lo que significa implementar estos métodos:
GetIDsOfNames
GetTypeInfo
GetTypeInfoCount
Invoke
Implemente IDispatch
como se describe en Bibliotecas de tipos y el lenguaje de descripción de objetos. Para obtener más información sobre la IDispatch
herencia y los métodos, vea IDispatch interface (oaidl.h).
Si el objeto que desea agregar a JavaScript aún no implementa IDispatch
, debe escribir un IDispatch
contenedor de clases para el objeto que desea exponer.
Es posible que haya bibliotecas para hacerlo automáticamente. Para obtener más información sobre los pasos necesarios para escribir un IDispatch
contenedor de clases para el objeto que desea exponer, consulte Automatización.
A continuación, guarde los cambios realizados en el proyecto.
En el Explorador de soluciones, haga clic con el botón derecho en WebView2APISample (que es la aplicación de ejemplo win32) y, a continuación, seleccione Compilar. Esto crea un archivo de biblioteca
.tlb
de tipos COM. Debe hacer referencia al.tlb
archivo desde el código fuente de C++. Para obtener más información, vea Biblioteca de tipos en COM, DCOM y Bibliotecas de tipos.
Paso 6: Llamar a AddHostObjectToScript para pasar el objeto host al código del lado web
Hasta ahora, hemos creado nuestra interfaz e implementado nuestro objeto host nativo. Ahora estamos listos para usar AddHostObjectToScript
para pasar el objeto host nativo al código JavaScript del lado web de la aplicación. La aplicación de ejemplo Win32 llama a AddHostObjectToScript
en ScenarioAddHostObject.cpp, como se muestra a continuación.
En el Explorador de soluciones de Visual Studio, abra WebView2APISample>Source Files>ScenarioAddHostObject.cpp.
Vaya a la implementación de clase
ScenarioAddHostObject
. Esta clase muestra HTML y controla la navegación: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); });
La
Make
instrucción muestra cómo crear una instancia delHostObjectSample
objeto COM que se definió en el archivo IDL. Este es el objeto que usaremos más adelante cuando llamemos aAddHostObjectToScript
. LaMake
instrucción nos obtiene un puntero a la interfaz que se implementa en HostObjectSampleImpl.cpp.A continuación, agregamos un controlador de eventos para escuchar el
NavigationStarting
evento: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());
En el
NavigationStarting
controlador de eventos, laquery_to
línea (a continuación) convierte el objeto COM recién creado en unIDispatch
tipo y, a continuación, convierte el objeto en .VARIANT
VARIANT
Los tipos permiten usar estructuras de datos como enteros y matrices, así como tipos más complejos comoIDispatch
.Para obtener una lista completa de los tipos de datos admitidos, vea Estructura VARIANT (oaidl.h). No todos los tipos de la
VARIANT
unión son compatibles conAddHostObjectToScript
. Para obtener más información, vea ICoreWebView2::AddHostObjectToScript (método).if (AreFileUrisEqual(sampleUri, uriTarget)) { VARIANT remoteObjectAsVariant = {}; m_hostObject.query_to<IDispatch>(&remoteObjectAsVariant.pdispVal); remoteObjectAsVariant.vt = VT_DISPATCH;
Ahora que tenemos una variante del objeto que es compatible con el código de C++, el código nativo de la aplicación de ejemplo está listo para pasar el objeto host al código del lado web de la aplicación.
En la línea inferior anterior, el
NavigationStarting
controlador de eventos establece el tipo variant del objeto remoto comoIDispatch
.// 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(); }
Anteriormente, en el
NavigationStarting
controlador de eventos,VARIANT
se pasa aAddHostObjectToScript
, con el nombresample
.
Paso 7: Acceso a los miembros del objeto host desde la página web JavaScript
En los pasos anteriores, el código nativo de la aplicación de ejemplo creó un objeto host que implementa IDispatch
. Este código nativo también llama a la API ICoreWebView2::AddHostObjectToScript
WebView2 o ICoreWebView2Frame::AddHostObjectToScriptWithOrigins
y pasa el objeto host al código del lado web de la aplicación.
Ahora el código del lado web de la aplicación puede acceder a las API de lado nativo que expone el objeto host. Las instrucciones de JavaScript en el .html
elemento de página web script
o en un archivo JavaScript al que se hace .js
referencia pueden acceder a las API de lado nativo exportadas.
El código del lado web de la aplicación de ejemplo Win32 ahora puede acceder a las propiedades y métodos del objeto host nativo para acceder a las API nativas. Usaremos los controles de página web de la aplicación de ejemplo, en la página webObjetos host de escenario> de la aplicación, para demostrarlo.
En Microsoft Visual Studio, seleccioneGuardar todo el archivo> (Ctrl+Mayús+S) para guardar el proyecto.
En el Explorador de soluciones, abra WebView2APISample>ScenarioAddHostObject.html. Compararemos este archivo con la página web correspondiente en la aplicación de ejemplo de Win32 en ejecución.
En el Explorador de soluciones, haga clic con el botón derecho en WebView2APISample (que es la aplicación de ejemplo win32) y, a continuación, seleccione Compilar.
Presione F5 para ejecutar el proyecto en modo de depuración.
En la aplicación de ejemplo Win32 (que tiene la barra de título de WebView2APISample), haga clic en el menú Escenario y, a continuación, seleccione el elemento de menú Objetos host . Aparece la página web de ejemplo AddHostObjectToScript , definida por
ScenarioAddHostObject.html
:La página web sugiere usar la herramienta Consola de DevTools para ejecutar instrucciones JavaScript en el
chrome.webview.hostObjects.sample
objeto . Si desea abrir DevTools desde la aplicación de ejemplo, haga clic con el botón derecho en la página y, a continuación, seleccione Inspeccionar. A continuación, seleccione la pestaña Consola . Para obtener más información, consulte Información general de la consola.Para abrir DevTools, es posible que la presión de F12 no funcione en este contexto y que se desencadene una excepción. Si es así, en Visual Studio, seleccione Detener depuración y, a continuación, presione F5 para reiniciar la depuración. En la aplicación de ejemplo, seleccioneObjetos hostde escenario> de nuevo. Para obtener más información, vea Abrir DevTools con un enfoque distinto de F12 en Depurar aplicaciones WebView2 con Visual Studio.
En la parte inferior de la página de demostración Objetos host se duplican los miembros del objeto de demostración dentro de :
<iframe>
En la página de demostración representada de la aplicación de ejemplo, lea el texto de la etiqueta explicando los botones Fecha .
Haga clic en los botones Fecha . Se muestra una cadena de fecha debajo de los botones, como:
sample.dateProperty: Tue Nov 01 2022 12:45:25 GMT-0700 (Pacific Daylight Time)
Explore propiedades y métodos haciendo clic en los botones de la página web de demostración y escribiendo valores para ver cómo se comporta el código de ejemplo. Los botones muestran el acceso a las propiedades y métodos del objeto host desde el código del lado web de la aplicación.
Para obtener información sobre lo que sucede en JavaScript, examine el código siguiente en ScenarioAddHostObject.html.
El código siguiente es una propiedad de demostración
Date
, directamente dentro delbody
elemento :<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>
También puede leer el texto de la etiqueta anterior en la página de demostración representada de la aplicación de ejemplo, explicando el código del botón Fecha .
El código siguiente es una propiedad de demostración
Date
que se encapsula en uniframe
elemento que se crea dentro de unscript
elemento:// 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; });
La expresión
chrome.webview.hostObjects.sync.sample.dateProperty
es deldateProperty
objeto host nativo.En el
.idl
archivo HostObjectSample.idl, descrito anteriormente, la propiedad date se define como parte del objeto host.
Uso de la aplicación de ejemplo
Puede experimentar con el uso y la modificación de la aplicación de ejemplo win32. A continuación, siga el mismo patrón en su propia aplicación:
- Cree un objeto host en el código nativo de la aplicación.
- Pase el objeto host al código del lado web de la aplicación.
- Use el objeto host desde el código del lado web de la aplicación.
Para averiguar qué otras API hay en el ecosistema de objetos host, consulte WebView2 Win32 C++ ICoreWebView2.
Introducción a la referencia de API
Consulte Uso compartido de objetos web o host en Información general sobre las características y las API de WebView2.
Vea también
- Interoperabilidad web/nativa en Información general sobre las características y las API de WebView2.
- Uso de marcos en aplicaciones WebView2
- Llamada al código winRT del lado nativo desde el código del lado web
GitHub: