Trabalhar com conteúdo local em aplicativos WebView2
Além de carregar conteúdo remoto, o conteúdo também pode ser carregado localmente no WebView2. Há várias abordagens que podem ser usadas para carregar conteúdo local em um controle WebView2, incluindo:
- Navegando até uma URL de arquivo.
- Navegando até uma cadeia de caracteres HTML.
- Mapeamento do nome do host virtual.
- Manipulando o
WebResourceRequested
evento.
Essas abordagens são descritas abaixo.
Selecionando uma abordagem
As várias maneiras de carregar conteúdo local em um controle WebView2 dão suporte aos seguintes cenários:
Cenário | Navegando até uma URL de arquivo | Navegando até uma cadeia de caracteres HTML | Usando o mapeamento de nomes de host virtual | Usando WebResourceRequested |
---|---|---|---|---|
APIs DOM baseadas em origem | ✔️ | ❌ | ✔️ | ✔️ |
APIs DOM que exigem contexto seguro | ❌ | ❌ | ✔️ | ✔️ |
Conteúdo dinâmico | ❌ | ✔️ | ❌ | ✔️ |
Recursos web adicionais | ✔️ | ❌ | ✔️ | ✔️ |
Recursos web adicionais resolvidos no processo WebView2 | ✔️ | ❌ | ✔️ | ❌ |
Esses cenários são descritos em mais detalhes abaixo.
Carregando conteúdo local navegando até uma URL de arquivo
O WebView2 permite que as navegaçãos registrem URLs, carreguem HTML básico ou um PDF. Essa é a abordagem mais simples e eficiente para carregar conteúdo local. No entanto, ele é menos flexível do que as outras abordagens. Como em um navegador da Web, as URLs de arquivo são limitadas em alguns recursos:
O documento tem uma origem exclusiva para seu caminho de arquivo. Isso significa que as APIs Web que exigem uma origem como
localStorage
ouindexedDB
funcionarão, mas os dados armazenados não estarão disponíveis para outros documentos locais carregados de outros caminhos de arquivo.Algumas APIs Web são limitadas apenas para proteger URLs HTTPS e não estão disponíveis para documentos carregados por URLs de arquivo. Isso inclui APIs como
navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som,navigator.geolocation.getCurrentPosition()
acessar a localização do dispositivo ouNotification.requestPermission()
solicitar a permissão do usuário para exibir notificações.Para cada recurso, o caminho completo deve ser especificado.
Para permitir referências a outros arquivos locais de URIs de arquivo ou exibir arquivos XML com transformações XSL aplicadas, você pode definir o argumento do
--allow-file-access-from-files
navegador. Consulte Propriedade CoreWebView2EnvironmentOptions.AdditionalBrowserArguments.
Considerações sobre o carregamento de conteúdo local navegando até uma URL de arquivo
As URLs de arquivo se comportam como no navegador. Por exemplo, você não pode fazer um XMLHttpRequest
(XHR) em uma URL de arquivo, porque você não está trabalhando no contexto de uma página da Web.
Você deve especificar o caminho completo do arquivo para cada recurso. Por exemplo:
file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Recursos de origem cruzada
Ao especificar uma URL de arquivo, o aplicativo navega até um arquivo em disco, não para um domínio na rede. Como resultado, não é possível usar recursos de origem cruzada no documento resultante.
APIs DOM baseadas em origem
Um documento carregado por meio de uma URL de arquivo tem uma origem exclusiva para seu caminho de arquivo, assim como no navegador. APIs Web que exigem uma origem como localStorage
ou indexedDB
funcionarão. No entanto, documentos diferentes carregados de URLs de arquivo diferentes não são considerados da mesma origem e não terão acesso aos mesmos dados armazenados.
APIs DOM que exigem contexto seguro
Algumas APIs Web são limitadas apenas para proteger URLs HTTPS e não estão disponíveis para documentos carregados por URLs de arquivo. Isso inclui APIs como navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som, navigator.geolocation.getCurrentPosition()
acessar a localização do dispositivo ou Notification.requestPermission()
solicitar a permissão do usuário para exibir notificações. Consulte Contextos seguros no MDN para obter mais informações.
Conteúdo dinâmico
Ao carregar um documento por meio de uma URL de arquivo, o conteúdo do documento vem de arquivos estáticos em disco. Isso significa que não é possível modificar dinamicamente esse conteúdo local. Isso é diferente de carregar documentos de um servidor Web, em que cada resposta pode ser gerada dinamicamente.
Recursos web adicionais
A resolução de URL relativa também funciona para documentos carregados por meio de uma URL de arquivo. Isso significa que o documento carregado pode ter referências a recursos da Web adicionais, como CSS, script ou arquivos de imagem que também são atendidos por meio de URLs de arquivo.
Recursos web adicionais resolvidos no processo WebView2
As URLs de arquivo são resolvidas nos processos do WebView2. Essa é uma opção mais rápida do que WebResourceRequested
, que é resolvida no thread da interface do usuário do processo do aplicativo host.
APIs para carregar conteúdo local navegando até uma URL de arquivo
Exemplo de uma URL de arquivo
Esta seção mostra como é uma URL de arquivo para um caminho de arquivo de conteúdo local de forma independente da plataforma.
Um aplicativo WebView2 precisa codificar URLs de arquivo local usando um file:///
prefixo e encaminhar barras. Por exemplo, para o exemplo Demo To Do, o caminho seria:
file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Para copiar o caminho completo com o prefixo "arquivo" para um arquivo local:
Opcionalmente, clone o repositório Demos para que você tenha uma cópia local. Consulte Etapa 5: Clonar o repositório Demos na instalação da extensão DevTools para Visual Studio Code.
No Microsoft Edge, pressione Ctrl+O para abrir um arquivo. Abra um arquivo local
.html
, como o arquivoDemos/demo-to-do/index.html
clonado localmente:C:\Users\username\Documents\GitHub\Demos\demo-to-do\index.html
A barra de endereços inicialmente não mostra o
file:///
prefixo, mas começa com a letra da unidade:C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Clique na barra Endereço e pressione a tecla Home ou pressione Ctrl+A para selecionar todo o caminho.
Todo o caminho do arquivo, incluindo
file:///
, é copiado no buffer da área de transferência, para que você possa colar o caminho completo, incluindo ofile:///
prefixo:file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Veja também:
- Demonstração a fazer – página renderizada
- Demonstração a fazer - código-fonte
- Etapa 5: Clonar o repositório Demos na instalação da extensão DevTools para Visual Studio Code.
Exemplo de navegação para uma URL de arquivo
webView.CoreWebView2.Navigate(
"file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html");
Carregando conteúdo local navegando até uma cadeia de caracteres HTML
Outro método para carregar conteúdo local é o NavigateToString
método. Essa abordagem carrega o conteúdo no WebView2 diretamente de uma cadeia de caracteres. Isso pode ser útil se você estiver empacotando o conteúdo por meio do código do aplicativo ou se quiser criar dinamicamente o conteúdo.
Outro cenário em que navegar até uma cadeia de caracteres pode ser útil é se você quiser carregar conteúdo que não esteja acessível por meio de uma URL. Por exemplo, se você tiver uma representação na memória de um documento HTML, poderá usar o NavigateToString
método para carregar esse conteúdo no controle WebView2. Isso pode ser útil se você quiser evitar a necessidade de gravar o conteúdo em um arquivo ou servidor antes de carregá-lo no controle.
Considerações sobre o carregamento de conteúdo local navegando até uma cadeia de caracteres HTML
APIs DOM baseadas em origem
Um documento carregado usando o NavigateToString
método tem sua localização definida como about:blank
e sua origem definida como null
. Isso significa que as APIs web que dependem de uma origem que está sendo definida, como localStorage
ou indexedDB
, não podem ser usadas.
APIs DOM que exigem contexto seguro
Algumas APIs Web são limitadas apenas para proteger URLs HTTPS e não estão disponíveis para documentos carregados por meio do NavigateToString
método porque sua localização está definida como about:blank
. Isso inclui APIs como navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som, navigator.geolocation.getCurrentPosition()
acessar a localização do dispositivo ou Notification.requestPermission()
solicitar a permissão do usuário para exibir notificações. Consulte Contextos seguros no MDN para obter mais informações.
Conteúdo dinâmico
Ao carregar conteúdo local por meio do NavigateToString
método, você está fornecendo diretamente o conteúdo como um parâmetro para o método. Isso significa que você está no controle do conteúdo em runtime e pode gerá-lo dinamicamente, se necessário.
Recursos web adicionais
Carregar conteúdo local usando o NavigateToString
método não torna possível que o documento resultante faça referência a recursos adicionais da Web, como CSS, imagem ou arquivos de script. O método só permite especificar o conteúdo da cadeia de caracteres do documento HTML. Para fazer referência a recursos web adicionais do documento HTML, use uma das outras abordagens descritas neste artigo ou represente esses recursos Web adicionais embutidos no documento HTML.
Recursos web adicionais resolvidos no processo WebView2
NavigateToString
não dá suporte a recursos web adicionais, conforme mencionado acima.
APIs para carregar conteúdo local navegando até uma cadeia de caracteres HTML
Representação de cadeia de caracteres de exemplo de uma página da Web
A seguir está a representação de cadeia de caracteres da página da Web Demonstração para Fazer . A listagem abaixo adicionou o encapsulamento de linha para legibilidade. Na prática, essas linhas são concatenadas em uma única linha longa:
`<html lang="en"><head>\n
<meta charset="UTF-8">\n
<meta name="viewport" content="width=device-width, initial-scale=1.0">\n
<title>TODO app</title>\n
<link rel="stylesheet" href="styles/light-theme.css" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)">\n
<link rel="stylesheet" href="styles/dark-theme.css" media="(prefers-color-scheme: dark)">\n
<link rel="stylesheet" href="styles/base.css">\n
<link rel="stylesheet" href="styles/to-do-styles.css">\n
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📋
</text></svg>">\n
</head>\n\n
<body>\n
<h1>📋 My tasks</h1>\n
<form>\n
<div class="new-task-form" tabindex="0">\n
<label for="new-task">➕ Add a task</label>\n
<input id="new-task" autocomplete="off" type="text" placeholder="Try typing 'Buy milk'" title="Click to start adding a task">\n
<input type="submit" value="➡️">\n
</div>\n
<ul id="tasks"><li class="divider">No tasks defined</li></ul>\n
</form>\n\n \x3Cscript src="to-do.js">\x3C/script>\n \n\n
</body>
</html>`
Para obter a cadeia de caracteres acima:
Vá para Demonstração para Fazer.
Clique com o botão direito do mouse na página da Web e selecione Inspecionar para abrir o DevTools.
No Console de DevTools, insira:
document.body.parentElement.outerHTML
. O Console gera uma representação de cadeia de caracteres da página da Web:
Exemplo de navegação para uma cadeia de caracteres HTML
// Define htmlString with the string representation of HTML as above.
webView.CoreWebView2.NavigateToString(htmlString);
Carregando conteúdo local usando o mapeamento de nome do host virtual
Outra maneira de carregar conteúdo local em um controle WebView2 é usar o mapeamento de nome do host virtual. Isso envolve mapear um nome de domínio local para uma pasta local, de modo que, quando o controle WebView2 tentar carregar um recurso para esse domínio, ele carregará o conteúdo do local da pasta local especificado. A origem do documento também será o nome do host virtual.
Essa abordagem permite especificar o acesso entre origens usando o CoreWebView2HostResourceAccessKind
enum.
Devido a uma limitação atual, os arquivos de mídia acessados usando um nome de host virtual podem ser lentos para carregar.
Considerações sobre o carregamento de conteúdo local usando o mapeamento de nome do host virtual
APIs DOM baseadas em origem
O conteúdo local carregado por meio do mapeamento de nome do host virtual resulta em um documento que tem uma URL HTTP ou HTTPS e uma origem correspondente. Isso significa que as APIs Web que exigem uma origem, como localStorage
ou indexedDB
funcionarão, e outros documentos que pertencem à mesma origem poderão usar os dados armazenados. Para obter mais informações, consulte Política de mesma origem no MDN.
APIs DOM que exigem contexto seguro
Algumas APIs Web são limitadas apenas para proteger URLs HTTPS. O uso do mapeamento de nome do host virtual fornece uma URL HTTPS para seu conteúdo local. Isso significa que APIs como navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som, navigator.geolocation.getCurrentPosition()
acessar a localização do dispositivo ou Notification.requestPermission()
solicitar a permissão do usuário para exibir notificações estão disponíveis. Consulte Contextos seguros no MDN para obter mais informações.
Conteúdo dinâmico
Ao carregar conteúdo local por meio de um mapeamento de nome do host virtual, você está mapeando um nome de host virtual para uma pasta local que contém arquivos estáticos em disco. Isso significa que não é possível modificar dinamicamente esse conteúdo local. Isso é diferente de carregar documentos de um servidor Web, em que cada resposta pode ser gerada dinamicamente.
Recursos web adicionais
O conteúdo local carregado por meio do mapeamento de nome do host virtual tem uma URL HTTP ou HTTPS que dá suporte à resolução de URL relativa. Isso significa que o documento carregado pode ter referências a recursos da Web adicionais, como CSS, script ou arquivos de imagem que também são atendidos por meio do mapeamento de nomes de host virtual.
Recursos web adicionais resolvidos no processo WebView2
As URLs de nome do host virtual são resolvidas nos processos do WebView2. Essa é uma opção mais rápida do que WebResourceRequested
, que é resolvida no thread da interface do usuário do processo do aplicativo host.
APIs para carregar conteúdo local usando o mapeamento de nome do host virtual
Exemplo de mapeamento de nome do host virtual
webView.CoreWebView2.SetVirtualHostNameToFolderMapping("demo",
"C:\Github\Demos\demo-to-do", CoreWebView2HostResourceAccessKind.DenyCors);
webView.CoreWebView2.Navigate("https://demo/index.html");
Carregando conteúdo local manipulando o evento WebResourceRequested
Outra maneira de hospedar conteúdo local em um controle WebView2 é confiando no WebResourceRequested
evento. Esse evento é disparado quando o controle tenta carregar um recurso. Você pode usar esse evento para interceptar a solicitação e fornecer o conteúdo local, conforme descrito no gerenciamento personalizado de solicitações de rede.
WebResourceRequested
permite personalizar o comportamento do conteúdo local por solicitação. Isso significa que você pode decidir para quais solicitações interceptar e fornecer seu próprio conteúdo e quais solicitações permitir que o controle WebView2 manipule normalmente. No entanto, personalizar o comportamento requer mais código, como mapeamento de host virtual, e requer conhecimento de HTTP, para poder construir uma resposta adequada.
Na perspectiva do WebView2, o recurso terá vindo por meio da rede e o WebView2 seguirá os cabeçalhos definidos pelo aplicativo como parte da resposta. O uso do WebResourceRequested
evento também é mais lento do que outras abordagens, devido à comunicação e processamento entre processos necessários para cada solicitação.
Registro de esquema personalizado
Se você quiser usar um esquema personalizado para fazer a Solicitação de Recursos da Web que gera o WebResourceRequested
evento, consulte Registro de esquema personalizado em Visão geral dos recursos e APIs do WebView2.
Considerações sobre o carregamento de conteúdo local manipulando o evento WebResourceRequested
APIs DOM baseadas em origem
O conteúdo local carregado por meio WebResourceRequested
resulta em um documento que tem uma URL HTTP ou HTTPS e uma origem correspondente. Isso significa que as APIs Web que exigem uma origem, como localStorage
ou indexedDB
funcionarão, e outros documentos que pertencem à mesma origem poderão usar os dados armazenados. Para obter mais informações, consulte Política de mesma origem no MDN.
APIs DOM que exigem contexto seguro
Algumas APIs Web são limitadas apenas para proteger URLs HTTPS. O uso WebResourceRequested
permite que você substitua solicitações de recurso Web da URL HTTPS pelo seu próprio conteúdo local. Isso significa que APIs como navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som, navigator.geolocation.getCurrentPosition()
acessar a localização do dispositivo ou Notification.requestPermission()
solicitar a permissão do usuário para exibir notificações estão disponíveis. Consulte Contextos seguros no MDN para obter mais informações.
Conteúdo dinâmico
Ao carregar conteúdo local por meio WebResourceRequested
do , você especifica o conteúdo local a ser carregado no manipulador de eventos. Isso significa que você está no controle do conteúdo em runtime e pode gerá-lo dinamicamente, se necessário.
Recursos web adicionais
WebResourceRequested
modifica o conteúdo carregado por meio de URLs HTTP ou HTTPS, que dão suporte à resolução de URL relativa. Isso significa que o documento resultante pode ter referências a recursos da Web adicionais, como CSS, script ou arquivos de imagem que também são atendidos por meio WebResourceRequested
de .
Recursos web adicionais resolvidos no processo WebView2
Ao carregar conteúdo por meio de uma URL de arquivo ou um mapeamento de nome de host virtual, a resolução acontece nos processos do WebView2. No entanto, o WebResourceRequested
evento é gerado no thread da interface do usuário do WebView2 do processo do aplicativo host, o que pode levar a um carregamento mais lento do documento resultante.
- O WebView2 faz uma primeira pausa no carregamento da página da Web para aguardar o envio do evento para o processo do aplicativo host.
- O WebView2 aguarda que o thread da interface do usuário esteja disponível.
- WebView2 aguarda o código do aplicativo para lidar com o evento.
Isso pode levar algum tempo. Certifique-se de limitar as chamadas AddWebResourceRequestedFilter
para apenas os recursos web que devem gerar o WebResourceRequested
evento.
APIs para carregar conteúdo local manipulando o evento WebResourceRequested
Exemplo de manipulação do evento WebResourceRequested
// Reading of response content stream happens asynchronously, and WebView2 does not
// directly dispose the stream once it read. Therefore, use the following stream
// class, which properly disposes when WebView2 has read all data. For details, see
// [CoreWebView2 does not close stream content](https://github.com/MicrosoftEdge/WebView2Feedback/issues/2513).
class ManagedStream : Stream {
public ManagedStream(Stream s)
{
s_ = s;
}
public override bool CanRead => s_.CanRead;
public override bool CanSeek => s_.CanSeek;
public override bool CanWrite => s_.CanWrite;
public override long Length => s_.Length;
public override long Position { get => s_.Position; set => s_.Position = value; }
public override void Flush()
{
throw new NotImplementedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
return s_.Seek(offset, origin);
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
int read = 0;
try
{
read = s_.Read(buffer, offset, count);
if (read == 0)
{
s_.Dispose();
}
}
catch
{
s_.Dispose();
throw;
}
return read;
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
private Stream s_;
}
webView.CoreWebView2.AddWebResourceRequestedFilter("https://demo/*",
CoreWebView2WebResourceContext.All);
webView.CoreWebView2.WebResourceRequested += delegate (object sender,
CoreWebView2WebResourceRequestedEventArgs args)
{
string assetsFilePath = "C:\\Demo\\" +
args.Request.Uri.Substring("https://demo/*".Length - 1);
try
{
FileStream fs = File.OpenRead(assetsFilePath);
ManagedStream ms = new ManagedStream(fs);
string headers = "";
if (assetsFilePath.EndsWith(".html"))
{
headers = "Content-Type: text/html";
}
else if (assetsFilePath.EndsWith(".jpg"))
{
headers = "Content-Type: image/jpeg";
} else if (assetsFilePath.EndsWith(".png"))
{
headers = "Content-Type: image/png";
}
else if (assetsFilePath.EndsWith(".css"))
{
headers = "Content-Type: text/css";
}
else if (assetsFilePath.EndsWith(".js"))
{
headers = "Content-Type: application/javascript";
}
args.Response = webView.CoreWebView2.Environment.CreateWebResourceResponse(
ms, 200, "OK", headers);
}
catch (Exception)
{
args.Response = webView.CoreWebView2.Environment.CreateWebResourceResponse(
null, 404, "Not found", "");
}
};
Confira também
- Gerenciar conteúdo carregado no WebView2 em Visão geral dos recursos e APIs do WebView2
- Página Demo To Do renderizada