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

  1. 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.

  2. 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.

  3. Abra Microsoft Visual Studio. Se recomienda abrir inicialmente el ejemplo win32 mediante Visual Studio 2019.

  4. En la copia local del repositorio clonadoWebView2Samples, abraSampleApps>WebView2Samples>WebView2Samples.sln. WebView2Samples.sln incluye el WebView2APISample 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.

  1. 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 hereda IUnknown como estándar para COM. Use esta IHostObjectSample 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();
    
        };
    
  2. Anteriormente, tenga en cuenta , DatePropertyque usa un DATE 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.

  1. En HostObjectSample.idl, examine la HostObjectSamplecoclase (clase de objeto de componente), que incluye las IHostObjectSample interfaces y IDispatch :

        [uuid(637abc45-11f7-4dde-84b4-317d62a638d3)]
        coclass HostObjectSample
        {
            [default] interface IHostObjectSample;
            interface IDispatch;
        };
    }
    
  2. La HostObjectSample coclase incluye interface IDispatch, que es necesario para que el objeto host funcione con AddHostObjectToScript.

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.

  1. En el Explorador de soluciones de Visual Studio, expanda WebView2APISample>Source Files y, a continuación, haga doble clic en HostObjectSampleImpl.cpp para abrirlo.

  2. 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();
    
  3. 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;
    }
    
  4. 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.

  1. A continuación, guarde los cambios realizados en el proyecto.

  2. 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.

  1. En el Explorador de soluciones de Visual Studio, abra WebView2APISample>Source Files>ScenarioAddHostObject.cpp.

  2. 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);
        });
    
  3. La Make instrucción muestra cómo crear una instancia del HostObjectSample objeto COM que se definió en el archivo IDL. Este es el objeto que usaremos más adelante cuando llamemos a AddHostObjectToScript. La Make instrucción nos obtiene un puntero a la interfaz que se implementa en HostObjectSampleImpl.cpp.

  4. 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());
    
  5. En el NavigationStarting controlador de eventos, la query_to línea (a continuación) convierte el objeto COM recién creado en un IDispatch 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 como IDispatch.

    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 con AddHostObjectToScript. 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.

  6. En la línea inferior anterior, el NavigationStarting controlador de eventos establece el tipo variant del objeto remoto como 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();
            }
    
  7. Anteriormente, en el NavigationStarting controlador de eventos, VARIANT se pasa a AddHostObjectToScript, con el nombre sample.

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.

  1. En Microsoft Visual Studio, seleccioneGuardar todo el archivo> (Ctrl+Mayús+S) para guardar el proyecto.

  2. 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.

  3. 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.

  4. Presione F5 para ejecutar el proyecto en modo de depuración.

  5. 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:

    Página de demostración de la parte superior de objetos host

  6. 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>

    Parte inferior de la página de demostración de objetos host

  7. En la página de demostración representada de la aplicación de ejemplo, lea el texto de la etiqueta explicando los botones Fecha .

  8. 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)
    
  9. 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.

  10. 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 del body 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 .

  11. El código siguiente es una propiedad de demostración Date que se encapsula en un iframe elemento que se crea dentro de un script 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; 
    });
    
  12. La expresión chrome.webview.hostObjects.sync.sample.dateProperty es del dateProperty 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:

  1. Cree un objeto host en el código nativo de la aplicación.
  2. Pase el objeto host al código del lado web de la aplicación.
  3. 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

GitHub: