Partilhar via


Chamar código do lado nativo a partir do código do lado da Web

O WebView2 permite às aplicações colmatar a lacuna entre os lados Web e nativo de uma aplicação ao permitir que um objeto seja transmitido para a Web. Expõe as APIs nativas selecionadas no JavaScript da sua página Web através de um objeto anfitrião nativo intermediário definido no código nativo. As APIs nativas são projetadas em JavaScript com a API WebView2 AddHostObjectToScript .

Este artigo abrange principalmente Win32/C++, e abrange também alguns aspetos do .NET/C# dentro de frames. Para WinRT, consulte Chamar código WinRT do lado nativo a partir do código do lado da Web.

Porquê utilizar AddHostObjectToScript?

  • Ao desenvolver uma aplicação WebView2, pode encontrar um objeto nativo cujos métodos ou propriedades acha úteis. Poderá querer acionar estes métodos de objeto nativo a partir do código do lado da Web, como resultado da interação do utilizador no lado Web da sua aplicação. Além disso, poderá não querer voltar a implementar os métodos dos objetos nativos no código do lado da Web. A AddHostObjectToScript API permite a reutilização do código do lado nativo por código do lado da Web.

  • Por exemplo, pode existir uma API web nativa, o que exigiria reescrever uma grande quantidade de código no lado da Web. Ter a capacidade de chamar os métodos do objeto nativo é mais rápido e eficiente do que voltar a codificar os métodos do objeto no lado Web da sua aplicação. Neste caso, o código do lado nativo pode transmitir o objeto para o código JavaScript do lado da Web da sua aplicação, para que o código JavaScript possa reutilizar os métodos da API nativa.

Cenários que podem beneficiar da utilização de objetos de anfitrião no script:

  • Existe uma API de teclado e pretende chamar a função a keyboardObject.showKeyboard partir do lado da Web.

  • Aceder ao sistema de ficheiros, não apenas ao sandbox da página Web, através de JavaScript. O JavaScript é em sandbox, o que o impede de aceder diretamente ao sistema de ficheiros. Ao utilizar AddHostObjectToScript para criar um objeto nativo exposto ao JavaScript, pode utilizar o objeto anfitrião para manipular ficheiros no sistema de ficheiros e não apenas no sandbox da página Web.

Este artigo utiliza a aplicação de exemplo Win32 para demonstrar algumas aplicações práticas do AddHostObjectToScript.

Passo 1: Instalar o Visual Studio, instalar o git, clonar o repositório WebView2Samples e abrir a solução

  1. Transfira e instale o Microsoft Visual Studio 2019 (versão 16.11.10) ou posterior e outros pré-requisitos, conforme descrito na aplicação de exemplo Win32. A aplicação de exemplo Win32 foi criada com o Visual Studio 2019, pelo que, para seguir os passos de exemplo neste artigo, recomendamos que comece com o Visual Studio 2019 em vez do Visual Studio 2022.

  2. Clone o repositório WebView2Samples . O repositório inclui a aplicação WebView2 específica do Win32. Para obter instruções, numa nova janela ou separador, consulte Win32 sample app (Aplicação de exemplo Win32).

  3. Abra o Microsoft Visual Studio. Recomendamos que abra inicialmente o exemplo Win32 com o Visual Studio 2019.

  4. Na cópia local do repositório clonadoWebView2Samples, abraSampleApps>WebView2Samples>WebView2Samples.sln. WebView2Samples.sln inclui o WebView2APISample projeto, que é a aplicação de exemplo Win32. Mantenha a solução de aplicação de exemplo aberta, para acompanhar o resto deste artigo.

Passo 2: definir a interface COM do objeto anfitrião com o IDL

Defina a interface COM do objeto anfitrião num .idl ficheiro, como HostObjectSample.idl, para descrever os métodos e propriedades no objeto anfitrião.

Primeiro, utilize idioma de definição de interface (IDL) para definir a interface COM do objeto anfitrião. Esta definição de objeto anfitrião num idl ficheiro descreve as propriedades e métodos nativos expostos (ou "moldados"). O ficheiro IDL (.idl) define uma interface, mas não a implementa.

  1. No Explorador de Soluções do Visual Studio, expanda WebView2APISample>Source Files e, em seguida, faça duplo clique HostObjectSample.idl para abri-lo.

    O código seguinte define a IHostObjectSample interface, que herda IUnknown como é padrão para COM. Utilize esta IHostObjectSample definição como modelo para definir os métodos, propriedades, funções de chamada de retorno do 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. Acima, tenha em atenção o DateProperty, que utiliza um DATE tipo. Vamos focar-nos nesta propriedade de demonstração de data neste artigo.

Passo 3: Definir uma coclasse de objeto anfitrião

Em seguida, o exemplo define a HostObjectSample coclasse a incluir IHostObjectSample e IDispatch.

  1. No HostObjectSample.idl, examine a HostObjectSamplecoclasse (classe de objeto de componente), que inclui as IHostObjectSample interfaces e IDispatch :

        [uuid(637abc45-11f7-4dde-84b4-317d62a638d3)]
        coclass HostObjectSample
        {
            [default] interface IHostObjectSample;
            interface IDispatch;
        };
    }
    
  2. A HostObjectSample coclasse inclui interface IDispatch, que é necessário para que o objeto anfitrião funcione com AddHostObjectToScript.

Passo 4: Implementar os membros do objeto C++

No código da aplicação de exemplo Win32, HostObjectSampleImpl.cpp utiliza a estrutura criada no ficheiro IDL COM e implementa cada membro do objeto C++. Este ficheiro C++ (.cpp) implementa a interface definida (e também implementa IDispatch).

Implemente todas as funções que estão definidas na interface do objeto, conforme descrevemos no ficheiro IDL. Certifique-se de que implementa as funções necessárias para IDispatch. O compilador emitirá um erro se estas funções não estiverem definidas.

Em seguida, vamos examinar duas propriedades específicas que foram definidas no IDL, para mostrar como o IDL está relacionado com o .cpp ficheiro.

  1. No Explorador de Soluções do Visual Studio, expanda WebView2APISample>Source Files e, em seguida, faça duplo clique HostObjectSampleImpl.cpp para abri-lo.

  2. Examine as declarações de propriedade em 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 a implementação das propriedades do objeto no 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 analisamos ao longo deste artigo.

Passo 5: Implementar o IDispatch

O objeto anfitrião tem de ser implementado IDispatch para que o WebView2 possa projetar o objeto anfitrião nativo no código do lado da Web da aplicação.

IDispatch permite-lhe invocar dinamicamente métodos e propriedades. Normalmente, chamar objetos requer invocações estáticas, mas pode utilizar JavaScript para criar dinamicamente chamadas de objeto. No código da aplicação de exemplo Win32, HostObjectSampleImpl.cpp implementa IDispatch, o que significa implementar estes métodos:

  • GetIDsOfNames
  • GetTypeInfo
  • GetTypeInfoCount
  • Invoke

Implemente IDispatch conforme descrito em Bibliotecas de Tipos e na Linguagem de Descrição do Objeto. Para obter mais informações sobre IDispatch a herança e os métodos, veja IDispatch interface (oaidl.h).

Se o objeto que pretende adicionar ao JavaScript ainda não implementar IDispatch, terá de escrever um IDispatch wrapper de classe para o objeto que pretende expor.

Poderão existir bibliotecas para o fazer automaticamente. Para saber mais sobre os passos necessários para escrever um IDispatch wrapper de classe para o objeto que pretende expor, veja Automatização.

  1. Em seguida, guarde as alterações efetuadas no projeto.

  2. No Explorador de Soluções, clique com o botão direito do rato em WebView2APISample (que é a aplicação de exemplo Win32) e, em seguida, selecione Compilar. Esta ação cria um ficheiro de biblioteca .tlb de tipo COM. Tem de referenciar o ficheiro a .tlb partir do código fonte C++. Para obter mais informações, veja Type Library in COM, DCOM, and Type Libraries (Biblioteca de Tipos em COM, DCOM e Bibliotecas de Tipos).

Passo 6: Chamar AddHostObjectToScript para passar o objeto anfitrião para o código do lado da Web

Até agora, criámos a nossa interface e implementámos o nosso objeto anfitrião nativo. Agora, estamos prontos para utilizar AddHostObjectToScript para transmitir o objeto anfitrião nativo para o código JavaScript do lado da Web da nossa aplicação. A aplicação de exemplo Win32 chama AddHostObjectToScript no ScenarioAddHostObject.cpp, conforme mostrado abaixo.

  1. No Explorador de Soluções do Visual Studio, abra WebView2APISample>Source Files>ScenarioAddHostObject.cpp.

  2. Aceda à implementação da ScenarioAddHostObject classe. Esta classe apresenta HTML e processa a navegação:

    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. A Make instrução mostra como instanciar o HostObjectSample objeto COM que foi definido no ficheiro IDL. Este é o objeto que utilizaremos mais tarde quando chamarmos AddHostObjectToScript. A Make instrução dá-nos um ponteiro para a interface implementada no HostObjectSampleImpl.cpp.

  4. Em seguida, adicionamos um processador de eventos para escutar o 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. No processador NavigationStarting de eventos, a query_to linha (abaixo) converte o objeto COM recentemente criado num IDispatch tipo e, em seguida, converte o objeto num VARIANT. VARIANT os tipos permitem-lhe utilizar estruturas de dados, como números inteiros e matrizes, bem como tipos mais complexos, como IDispatch.

    Para obter uma lista completa dos tipos de dados suportados, veja Estrutura VARIANT (oaidl.h). Nem todos os tipos no VARIANT sindicato são suportados pelo AddHostObjectToScript. Para obter detalhes, consulte o método ICoreWebView2::AddHostObjectToScript.

            if (AreFileUrisEqual(sampleUri, uriTarget))
            {
                VARIANT remoteObjectAsVariant = {};
                m_hostObject.query_to<IDispatch>(&remoteObjectAsVariant.pdispVal);
                remoteObjectAsVariant.vt = VT_DISPATCH;
    

    Agora que temos uma variante do objeto compatível com o código C++, o código nativo da aplicação de exemplo está pronto para transmitir o objeto anfitrião ao código do lado da Web da aplicação.

  6. Na linha de fundo acima, o NavigationStarting processador de eventos define o tipo de variante do 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. Acima, no processador de NavigationStarting eventos, o VARIANT é transmitido para AddHostObjectToScript, com o nome sample.

Passo 7: Aceder aos membros do objeto anfitrião a partir da página Web JavaScript

Nos passos acima, o código nativo da aplicação de exemplo criou um objeto anfitrião que implementa IDispatch. Este código nativo também chama a API ICoreWebView2::AddHostObjectToScript WebView2 ou ICoreWebView2Frame::AddHostObjectToScriptWithOrigins e transmite o objeto anfitrião para o código do lado da Web da aplicação.

Agora, o código do lado da Web da aplicação pode aceder às APIs nativas que são expostas pelo objeto anfitrião. As instruções JavaScript no elemento da página .html Web script ou num ficheiro JavaScript referenciado .js podem aceder às APIs do lado nativo exportadas.

O código do lado da Web da aplicação de exemplo Win32 consegue agora aceder às propriedades e métodos do objeto anfitrião nativo para aceder às APIs nativas. Vamos utilizar os controlos de página Web da aplicação de exemplo, na página WebObjetos de Anfitrião do Cenário> da aplicação, para demonstrar isto.

  1. No Microsoft Visual Studio, selecioneGuardar Todos osFicheiros> (Ctrl+Shift+S) para guardar o projeto.

  2. No Explorador de Soluções, abra WebView2APISample>ScenarioAddHostObject.html. Vamos comparar este ficheiro com a página Web correspondente na aplicação de exemplo Win32 em execução.

  3. No Explorador de Soluções, clique com o botão direito do rato em WebView2APISample (que é a aplicação de exemplo Win32) e, em seguida, selecione Compilar.

  4. Prima F5 para executar o projeto no modo de Depuração.

  5. Na aplicação de exemplo Win32 (que tem a barra de título de WebView2APISample), clique no menu Cenário e, em seguida, selecione o menuItem Objetos de Anfitrião . É apresentada a página Web De Exemplo AddHostObjectToScript , definida por ScenarioAddHostObject.html:

    Página de demonstração Top of Host Objects

  6. A página Web sugere a utilização da ferramenta consola de DevTools para executar instruções JavaScript no chrome.webview.hostObjects.sample objeto. Se quiser abrir o DevTools a partir da aplicação de exemplo, clique com o botão direito do rato na página e, em seguida, selecione Inspecionar. Em seguida, selecione o separador Consola . Para obter mais informações, veja Descrição geral da consola.

    Para abrir DevTools, premir F12 pode não funcionar neste contexto e pode acionar uma exceção. Se for o caso, no Visual Studio, selecione Parar Depuração e, em seguida, prima F5 para reiniciar a depuração. Na aplicação de exemplo, selecioneObjetos de Anfitrião do Cenário> novamente. Para obter mais informações, veja Open DevTools using an approach other than F12 in Debug WebView2 apps with Visual Studio (Abrir DevTools com uma abordagem diferente de F12 em Depurar aplicações WebView2 com o Visual Studio).

    A parte inferior da página de demonstração Objetos anfitriões duplica os membros do objeto de demonstração num <iframe>:

    Parte inferior da página de demonstração Objetos anfitriões

  7. Na página de demonstração composta na aplicação de exemplo, leia o texto da etiqueta que explica os botões Data .

  8. Clique nos botões Data . É apresentada uma cadeia de data abaixo dos botões, tais como:

    sample.dateProperty: Tue Nov 01 2022 12:45:25 GMT-0700 (Pacific Daylight Time)
    
  9. Explore as propriedades e os métodos ao clicar nos botões na página Web de demonstração e introduzir valores para ver o comportamento do código de exemplo. Os botões demonstram o acesso às propriedades e métodos do objeto anfitrião a partir do código do lado da Web da aplicação.

  10. Para obter informações sobre o que está a acontecer no JavaScript, examine o seguinte código no ScenarioAddHostObject.html.

    O código seguinte é uma propriedade de demonstração Date , diretamente dentro do 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>
    

    Também pode ler o texto da etiqueta acima na página de demonstração composta na aplicação de exemplo, explicando o código do botão Data .

  11. O código seguinte é uma propriedade de demonstração Date que está encapsulada num iframe elemento criado num 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. A expressão chrome.webview.hostObjects.sync.sample.dateProperty é do dateProperty objeto anfitrião nativo.

    .idl No ficheiro HostObjectSample.idl, descrito anteriormente, a propriedade date é definida como parte do objeto anfitrião.

Utilizar a aplicação de exemplo

Pode experimentar utilizar e modificar a aplicação de exemplo Win32. Em seguida, siga o mesmo padrão na sua própria aplicação:

  1. Crie um objeto anfitrião no código nativo da sua aplicação.
  2. Transmita o objeto anfitrião para o código do lado da Web da sua aplicação.
  3. Utilize o objeto anfitrião do código do lado da Web da aplicação.

Para saber que outras APIs existem no ecossistema de objetos anfitriões, consulte WebView2 Win32 C++ ICoreWebView2.

Descrição geral da Referência da API

Veja Partilha de objetos Anfitrião/Web na Descrição geral das funcionalidades e APIs do WebView2.

Confira também

GitHub: