Trabalhar com conteúdo local em aplicações WebView2
Além de carregar conteúdo remoto, o conteúdo também pode ser carregado localmente para o WebView2. Existem várias abordagens que podem ser utilizadas para carregar conteúdo local para um controlo WebView2, incluindo:
- Navegar para um URL de ficheiro.
- Navegar para uma cadeia HTML.
- Mapeamento de nomes de anfitrião virtual.
- A processar o
WebResourceRequested
evento.
Estas abordagens são descritas abaixo.
Selecionar uma abordagem
As várias formas de carregar conteúdo local para um controlo WebView2 suportam os seguintes cenários:
Cenário | Ao navegar para um URL de ficheiro | Ao navegar para uma cadeia HTML | Ao utilizar o mapeamento de nomes de anfitrião virtual | Ao utilizar WebResourceRequested |
---|---|---|---|---|
APIs DOM baseadas na origem | ✔️ | ❌ | ✔️ | ✔️ |
APIs DOM que requerem contexto seguro | ❌ | ❌ | ✔️ | ✔️ |
Conteúdo dinâmico | ❌ | ✔️ | ❌ | ✔️ |
Recursos Web adicionais | ✔️ | ❌ | ✔️ | ✔️ |
Recursos Web adicionais resolvidos no processo WebView2 | ✔️ | ❌ | ✔️ | ❌ |
Estes cenários são descritos mais detalhadamente abaixo.
Carregar conteúdo local ao navegar para um URL de ficheiro
O WebView2 permite navegação para URLs de ficheiros, para carregar HTML básico ou um PDF. Esta é a abordagem mais simples e eficiente para carregar conteúdo local. No entanto, é menos flexível do que as outras abordagens. Tal como num browser, os URLs de ficheiros são limitados em algumas capacidades:
O documento tem uma origem exclusiva para o respetivo caminho de ficheiro. Isto significa que as APIs Web que requerem uma origem, como
localStorage
ouindexedDB
irão funcionar, mas os dados armazenados não estarão disponíveis para outros documentos locais carregados a partir de outros caminhos de ficheiro.Algumas APIs Web estão limitadas apenas a URLs HTTPS seguros e não estão disponíveis para documentos carregados por URLs de ficheiro. Isto inclui APIs como
navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som,navigator.geolocation.getCurrentPosition()
aceder à localização do dispositivo ouNotification.requestPermission()
pedir a permissão do utilizador para apresentar notificações.Para cada recurso, o caminho completo tem de ser especificado.
Para permitir referências a outros ficheiros locais a partir de URIs de ficheiros ou para apresentar ficheiros XML com transformações XSL aplicadas, pode definir o argumento do
--allow-file-access-from-files
browser. Veja CoreWebView2EnvironmentOptions.AdditionalBrowserArguments Property (Propriedade CoreWebView2EnvironmentOptions.AdditionalBrowserArguments).
Considerações para carregar conteúdo local ao navegar para um URL de ficheiro
Os URLs dos ficheiros comportam-se como no browser. Por exemplo, não pode criar um XMLHttpRequest
(XHR) num URL de ficheiro, porque não está a trabalhar no contexto de uma página Web.
Tem de especificar o caminho completo do ficheiro para cada recurso. Por exemplo:
file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Recursos de várias origens
Ao especificar um URL de ficheiro, a aplicação navega para um ficheiro no disco e não para um domínio na rede. Como resultado, não é possível utilizar recursos de várias origens no documento resultante.
APIs DOM baseadas na origem
Um documento carregado através de um URL de ficheiro tem uma origem exclusiva do respetivo caminho de ficheiro, tal como no browser. AS APIs Web que necessitam de uma origem, como localStorage
ou indexedDB
irão funcionar. No entanto, diferentes documentos carregados a partir de URLs de ficheiros diferentes não são considerados como provenientes da mesma origem e não terão acesso aos mesmos dados armazenados.
APIs DOM que requerem contexto seguro
Algumas APIs Web estão limitadas apenas a URLs HTTPS seguros e não estão disponíveis para documentos carregados por URLs de ficheiro. Isto inclui APIs como navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som, navigator.geolocation.getCurrentPosition()
aceder à localização do dispositivo ou Notification.requestPermission()
pedir a permissão do utilizador para apresentar notificações. Veja Contextos seguros no MDN para obter mais informações.
Conteúdo dinâmico
Ao carregar um documento através de um URL de ficheiro, o conteúdo do documento provém de ficheiros estáticos no disco. Isto significa que não é possível modificar dinamicamente este conteúdo local. Isto é diferente de carregar documentos a partir de um servidor Web, onde cada resposta pode ser gerada dinamicamente.
Recursos Web adicionais
A resolução de URL relativa também funciona para documentos carregados através de um URL de ficheiro. Isto significa que o documento carregado pode ter referências a recursos Web adicionais, como CSS, script ou ficheiros de imagem, que também são servidos através de URLs de ficheiro.
Recursos Web adicionais resolvidos no processo WebView2
Os URLs de ficheiro são resolvidos nos processos webView2. Esta é uma opção mais rápida do que WebResourceRequested
, que é resolvida no thread de IU do processo da aplicação anfitriã.
APIs para carregar conteúdo local ao navegar para um URL de ficheiro
Exemplo de um URL de ficheiro
Esta secção mostra o aspeto de um URL de ficheiro para um caminho de ficheiro de conteúdo local de uma forma independente da plataforma.
Uma aplicação WebView2 tem de codificar URLs de ficheiro local com um file:///
prefixo e 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 "ficheiro" para um ficheiro local:
Opcionalmente, clone o repositório Demos para que tenha uma cópia local. Veja Passo 5: Clonar o repositório Demos em Instalar a extensão DevTools para o Visual Studio Code.
No Microsoft Edge, prima Ctrl+O para abrir um ficheiro. Abra um ficheiro local
.html
, como o ficheiroDemos/demo-to-do/index.html
clonado localmente:C:\Users\username\Documents\GitHub\Demos\demo-to-do\index.html
Inicialmente, a Barra de endereço não mostra o
file:///
prefixo, mas começa com a letra de unidade:C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Clique na Barra de endereço e, em seguida, prima a tecla Base ou prima Ctrl+A para selecionar todo o caminho.
Todo o caminho do ficheiro, incluindo
file:///
, é copiado para a memória intermédia da área de transferência, para que 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 composta
- Demonstração a Fazer - código fonte
- Passo 5: Clone o repositório Demos em Instalar a extensão DevTools para o Visual Studio Code.
Exemplo de navegação para um URL de ficheiro
webView.CoreWebView2.Navigate(
"file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html");
Carregar conteúdo local ao navegar para uma cadeia HTML
Outro método para carregar conteúdo local é o NavigateToString
método . Esta abordagem carrega o conteúdo para o WebView2 diretamente a partir de uma cadeia. Isto pode ser útil se estiver a empacotar o conteúdo através do código da aplicação ou se quiser criar dinamicamente o conteúdo.
Outro cenário em que navegar para uma cadeia pode ser útil se quiser carregar conteúdo que não esteja acessível através de um URL. Por exemplo, se tiver uma representação dentro da memória de um documento HTML, pode utilizar o NavigateToString
método para carregar esse conteúdo para o controlo WebView2. Isto pode ser útil se quiser evitar a necessidade de escrever o conteúdo num ficheiro ou servidor antes de o carregar para o controlo.
Considerações para carregar conteúdo local ao navegar para uma cadeia HTML
A cadeia de conteúdo HTML que é transmitida para o NavigateToString
método tem um limite de tamanho de 2 MB. Este limite de tamanho pode ser fácil de exceder quando a cadeia inclui recursos adicionais indicados. Se este limite de tamanho for excedido, é devolvido um erro: "O valor não se enquadra no intervalo esperado".
APIs DOM baseadas na origem
Um documento carregado com o método tem a NavigateToString
localização definida como e a about:blank
origem definida como null
. Isto significa que as APIs Web que dependem de uma origem a ser definida, como localStorage
ou indexedDB
, não podem ser utilizadas.
APIs DOM que requerem contexto seguro
Algumas APIs Web estão limitadas apenas a URLs HTTPS seguros e não estão disponíveis para documentos carregados através do método porque a NavigateToString
localização está definida como about:blank
. Isto inclui APIs como navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som, navigator.geolocation.getCurrentPosition()
aceder à localização do dispositivo ou Notification.requestPermission()
pedir a permissão do utilizador para apresentar notificações. Veja Contextos seguros no MDN para obter mais informações.
Conteúdo dinâmico
Ao carregar conteúdo local através do NavigateToString
método , está a fornecer diretamente o conteúdo como um parâmetro para o método . Isto significa que controla o conteúdo no runtime e pode gerá-lo dinamicamente, se necessário.
Recursos Web adicionais
Carregar conteúdo local com o NavigateToString
método não permite que o documento resultante faça referência a recursos Web adicionais, como CSS, ficheiros de imagem ou script. O método só lhe permite especificar o conteúdo da cadeia de carateres do documento HTML. Para referenciar recursos Web adicionais do seu documento HTML, utilize uma das outras abordagens descritas neste artigo ou represente esses recursos Web adicionais inline no documento HTML.
Recursos Web adicionais resolvidos no processo WebView2
NavigateToString
não suporta recursos Web adicionais, conforme mencionado acima.
APIs para carregar conteúdo local ao navegar para uma cadeia HTML
Representação de cadeia de exemplo de uma página Web
Segue-se a representação da cadeia de carateres da página Web Demo To Do . A listagem abaixo adicionou moldagem de linhas para legibilidade. Na prática, estas linhas são concatenadas numa ú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 acima:
Aceda a Demonstração a Fazer.
Clique com o botão direito do rato na página Web e, em seguida, selecione Inspecionar para abrir DevTools.
Na Consola do DevTools, introduza:
document.body.parentElement.outerHTML
. A Consola produz uma representação de cadeia da página Web:
Exemplo de navegação para uma cadeia HTML
// Define htmlString with the string representation of HTML as above.
webView.CoreWebView2.NavigateToString(htmlString);
Carregar conteúdo local com o mapeamento de nomes de anfitrião virtual
Outra forma de carregar conteúdo local num controlo WebView2 é utilizar o mapeamento de nomes de anfitrião virtual. Isto envolve mapear um nome de domínio local para uma pasta local, para que, quando o controlo WebView2 tentar carregar um recurso para esse domínio, carregue o conteúdo a partir da localização da pasta local especificada. A origem do documento também será o nome do anfitrião virtual.
Esta abordagem permite-lhe especificar o acesso entre origens através da enumeração CoreWebView2HostResourceAccessKind
.
Devido a uma limitação atual, os ficheiros multimédia que são acedidos com um nome de anfitrião virtual podem ser lentos a carregar.
Considerações para carregar conteúdo local através do mapeamento de nomes de anfitrião virtual
APIs DOM baseadas na origem
O conteúdo local carregado através do mapeamento de nomes de anfitrião virtual resulta num documento que tem um URL HTTP ou HTTPS e uma origem correspondente. Isto significa que as APIs Web que necessitam de uma origem, como localStorage
ou indexedDB
irão funcionar, e outros documentos que pertencem à mesma origem poderão utilizar os dados armazenados. Para obter mais informações, veja Política de origem idêntica no MDN.
APIs DOM que requerem contexto seguro
Algumas APIs Web estão limitadas apenas a URLs HTTPS seguros. A utilização do mapeamento de nomes de anfitrião virtual fornece um URL HTTPS para o seu conteúdo local. Isto significa que as APIs, como navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som, navigator.geolocation.getCurrentPosition()
aceder à localização do dispositivo ou Notification.requestPermission()
pedir a permissão do utilizador para apresentar notificações estão disponíveis. Veja Contextos seguros no MDN para obter mais informações.
Conteúdo dinâmico
Ao carregar conteúdo local através de um mapeamento de nomes de anfitrião virtual, está a mapear um nome de anfitrião virtual para uma pasta local que contém ficheiros estáticos no disco. Isto significa que não é possível modificar dinamicamente este conteúdo local. Isto é diferente de carregar documentos a partir de um servidor Web, onde cada resposta pode ser gerada dinamicamente.
Recursos Web adicionais
O conteúdo local carregado através do mapeamento de nomes de anfitrião virtual tem um URL HTTP ou HTTPS que suporta a resolução de URL relativa. Isto significa que o documento carregado pode ter referências a recursos Web adicionais, como CSS, script ou ficheiros de imagem, que também são servidos através do mapeamento de nomes de anfitrião virtual.
Recursos Web adicionais resolvidos no processo WebView2
Os URLs do nome do anfitrião virtual são resolvidos em processos WebView2. Esta é uma opção mais rápida do que WebResourceRequested
, que é resolvida no thread de IU do processo da aplicação anfitriã.
APIs para carregar conteúdo local através do mapeamento de nomes de anfitrião virtual
Exemplo de mapeamento de nomes de anfitrião virtual
webView.CoreWebView2.SetVirtualHostNameToFolderMapping("demo",
"C:\Github\Demos\demo-to-do", CoreWebView2HostResourceAccessKind.DenyCors);
webView.CoreWebView2.Navigate("https://demo/index.html");
Carregar conteúdo local ao processar o evento WebResourceRequested
Outra forma de alojar conteúdo local num controlo WebView2 é dependendo do WebResourceRequested
evento. Este evento é acionado quando o controlo tenta carregar um recurso. Pode utilizar este evento para intercetar o pedido e fornecer o conteúdo local, conforme descrito em Gestão personalizada de pedidos de rede.
WebResourceRequested
permite-lhe personalizar o comportamento dos conteúdos locais numa base por pedido. Isto significa que pode decidir para que pedidos intercetar e fornecer o seu próprio conteúdo e quais os pedidos para permitir que o controlo WebView2 processe normalmente. No entanto, personalizar o comportamento requer mais código, como o mapeamento de anfitriões virtuais, e requer conhecimento de HTTP, para conseguir construir uma resposta adequada.
Na perspetiva do WebView2, o recurso terá vindo através da rede e o WebView2 irá cumprir os cabeçalhos definidos pela aplicação como parte da resposta. A utilização do WebResourceRequested
evento também é mais lenta do que outras abordagens, devido à comunicação e processamento entre processos necessários para cada pedido.
Registo de esquema personalizado
Se quiser utilizar um esquema personalizado para fazer o Pedido de Recurso Web que gera o WebResourceRequested
evento, veja Registo de esquema personalizado em Descrição geral das funcionalidades e APIs webView2.
Considerações para carregar conteúdo local ao processar o evento WebResourceRequested
APIs DOM baseadas na origem
Conteúdo local carregado através de WebResourceRequested
resultados num documento que tem um URL HTTP ou HTTPS e uma origem correspondente. Isto significa que as APIs Web que necessitam de uma origem, como localStorage
ou indexedDB
irão funcionar, e outros documentos que pertencem à mesma origem poderão utilizar os dados armazenados. Para obter mais informações, veja Política de origem idêntica no MDN.
APIs DOM que requerem contexto seguro
Algumas APIs Web estão limitadas apenas a URLs HTTPS seguros. A utilização WebResourceRequested
permite-lhe substituir pedidos de recursos Web de URL HTTPS pelo seu próprio conteúdo local. Isto significa que as APIs, como navigator.mediaDevices.getUserMedia()
adquirir vídeo ou som, navigator.geolocation.getCurrentPosition()
aceder à localização do dispositivo ou Notification.requestPermission()
pedir a permissão do utilizador para apresentar notificações estão disponíveis. Veja Contextos seguros no MDN para obter mais informações.
Conteúdo dinâmico
Ao carregar conteúdo local através WebResourceRequested
de , especifique o conteúdo local a carregar no processador de eventos. Isto significa que controla o conteúdo no runtime e pode gerá-lo dinamicamente, se necessário.
Recursos Web adicionais
WebResourceRequested
modifica o conteúdo carregado através de URLs HTTP ou HTTPS, que suportam a resolução relativa do URL. Isto significa que o documento resultante pode ter referências a recursos Web adicionais, como CSS, script ou ficheiros de imagem que também são servidos através do WebResourceRequested
.
Recursos Web adicionais resolvidos no processo WebView2
Ao carregar conteúdo através de um URL de ficheiro ou de um mapeamento de nome de anfitrião virtual, a resolução ocorre nos processos webView2. No entanto, o WebResourceRequested
evento é gerado no thread da IU webView2 do processo da aplicação anfitriã, o que pode levar a um carregamento mais lento do documento resultante.
- Primeiro, o WebView2 interrompe o carregamento da página Web para aguardar que o evento seja enviado para o processo da aplicação anfitriã.
- Em seguida, o WebView2 aguarda que o thread de IU esteja disponível.
- Em seguida, o WebView2 aguarda que o código da aplicação processe o evento.
Esta ação pode demorar algum tempo. Certifique-se de que limita as chamadas para AddWebResourceRequestedFilter
apenas para os recursos Web que têm de gerar o WebResourceRequested
evento.
APIs para carregar conteúdo local ao processar o evento WebResourceRequested
Exemplo de processamento 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
- Gerir conteúdos carregados para o WebView2 na Descrição geral das funcionalidades e APIs do WebView2
- Demo To Do rendered page