Trabajar con contenido local en aplicaciones WebView2
Además de cargar contenido remoto, el contenido también se puede cargar localmente en WebView2. Hay varios enfoques que se pueden usar para cargar contenido local en un control WebView2, entre los que se incluyen:
- Vaya a una dirección URL de archivo.
- Navegar a una cadena HTML.
- Asignación de nombres de host virtual.
- Control del
WebResourceRequested
evento.
Estos enfoques se describen a continuación.
Selección de un enfoque
Las distintas formas de cargar contenido local en un control WebView2 admiten los siguientes escenarios:
Escenario | Al navegar a una dirección URL de archivo | Al navegar a una cadena HTML | Mediante la asignación de nombres de host virtual | Mediante el uso de WebResourceRequested |
---|---|---|---|---|
API DOM basadas en origen | ✔️ | ❌ | ✔️ | ✔️ |
API dom que requieren contexto seguro | ❌ | ❌ | ✔️ | ✔️ |
Contenido dinámico | ❌ | ✔️ | ❌ | ✔️ |
Recursos web adicionales | ✔️ | ❌ | ✔️ | ✔️ |
Recursos web adicionales resueltos en el proceso WebView2 | ✔️ | ❌ | ✔️ | ❌ |
Estos escenarios se describen con más detalle a continuación.
Carga de contenido local navegando a una dirección URL de archivo
WebView2 permite la navegación a las direcciones URL de archivo, para cargar HTML básico o un PDF. Este es el enfoque más sencillo y eficaz para cargar contenido local. Sin embargo, es menos flexible que los demás enfoques. Al igual que en un explorador web, las direcciones URL de archivo están limitadas en algunas funcionalidades:
El documento tiene un origen que es único en su ruta de acceso de archivo. Esto significa que las API web que requieren un origen como
localStorage
oindexedDB
funcionarán, pero los datos almacenados no estarán disponibles para otros documentos locales cargados desde otras rutas de acceso de archivo.Algunas API web se limitan solo a las direcciones URL HTTPS seguras y no están disponibles para los documentos cargados por direcciones URL de archivo. Esto incluye API como
navigator.mediaDevices.getUserMedia()
adquirir vídeo o sonido,navigator.geolocation.getCurrentPosition()
acceder a la ubicación del dispositivo oNotification.requestPermission()
solicitar el permiso del usuario para mostrar notificaciones.Para cada recurso, se debe especificar la ruta de acceso completa.
Para permitir referencias a otros archivos locales desde uri de archivo o para mostrar archivos XML con transformaciones XSL aplicadas, puede establecer el argumento del
--allow-file-access-from-files
explorador. Vea CoreWebView2EnvironmentOptions.AdditionalBrowserArguments (propiedad).
Consideraciones para cargar contenido local navegando a una dirección URL de archivo
Las direcciones URL de archivo se comportan como en el explorador. Por ejemplo, no puede crear una XMLHttpRequest
(XHR) en una dirección URL de archivo, porque no está trabajando en el contexto de una página web.
Debe especificar la ruta de acceso completa del archivo para cada recurso. Por ejemplo:
file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Recursos entre orígenes
Al especificar una dirección URL de archivo, la aplicación navega a un archivo en disco, no a un dominio de la red. Como resultado, no es posible usar recursos entre orígenes en el documento resultante.
API DOM basadas en origen
Un documento cargado a través de una dirección URL de archivo tiene un origen que es único para su ruta de acceso de archivo, al igual que en el explorador. Las API web que requieren un origen como localStorage
o indexedDB
funcionarán. Sin embargo, los distintos documentos cargados de direcciones URL de archivo diferentes no se consideran del mismo origen y no tendrán acceso a los mismos datos almacenados.
API dom que requieren contexto seguro
Algunas API web se limitan solo a las direcciones URL HTTPS seguras y no están disponibles para los documentos cargados por direcciones URL de archivo. Esto incluye API como navigator.mediaDevices.getUserMedia()
adquirir vídeo o sonido, navigator.geolocation.getCurrentPosition()
acceder a la ubicación del dispositivo o Notification.requestPermission()
solicitar el permiso del usuario para mostrar notificaciones. Consulte Contextos seguros en MDN para obtener más información.
Contenido dinámico
Al cargar un documento a través de una dirección URL de archivo, el contenido del documento procede de un archivo estático en el disco. Esto significa que no es posible modificar dinámicamente este contenido local. Esto es diferente de cargar documentos desde un servidor web, donde cada respuesta se puede generar dinámicamente.
Recursos web adicionales
La resolución de direcciones URL relativas también funciona para los documentos cargados a través de una dirección URL de archivo. Esto significa que el documento cargado puede tener referencias a recursos web adicionales como CSS, scripts o archivos de imagen que también se proporcionan a través de direcciones URL de archivo.
Recursos web adicionales resueltos en el proceso WebView2
Las direcciones URL de archivo se resuelven en procesos de WebView2. Se trata de una opción más rápida que WebResourceRequested
, que se resuelve en el subproceso de interfaz de usuario del proceso de aplicación host.
API para cargar contenido local navegando a una dirección URL de archivo
Ejemplo de una dirección URL de archivo
En esta sección se muestra el aspecto de una dirección URL de archivo para una ruta de acceso de archivo de contenido local de forma independiente de la plataforma.
Una aplicación WebView2 debe codificar direcciones URL de archivo local con un file:///
prefijo y barras diagonales. Por ejemplo, para el ejemplo Demo To Do, la ruta de acceso sería:
file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Para copiar la ruta de acceso completa con el prefijo "file" para un archivo local:
Opcionalmente, clone el repositorio Demos para que tenga una copia local. Vea Paso 5: Clonar el repositorio de demostraciones en Instalación de la extensión DevTools para Visual Studio Code.
En Microsoft Edge, presione Ctrl+O para abrir un archivo. Abra un archivo local
.html
, como el archivoDemos/demo-to-do/index.html
clonado localmente:C:\Users\username\Documents\GitHub\Demos\demo-to-do\index.html
La barra de direcciones no muestra inicialmente el
file:///
prefijo, pero comienza con la letra de unidad:C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Haga clic en la barra Dirección y, a continuación, presione la tecla Inicio o presione Ctrl+A para seleccionar toda la ruta de acceso.
Toda la ruta de acceso del archivo, incluida
file:///
, se copia en el búfer del Portapapeles, por lo que puede pegar la ruta de acceso completa, incluido elfile:///
prefijo:file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
Vea también:
- Demostración de tareas pendientes: página representada
- Demostración de tareas pendientes: código fuente
- Paso 5: Clonar el repositorio Demos en Instalación de la extensión DevTools para Visual Studio Code.
Ejemplo de navegación a una dirección URL de archivo
webView.CoreWebView2.Navigate(
"file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html");
Carga de contenido local navegando a una cadena HTML
Otro método para cargar contenido local es el NavigateToString
método . Este enfoque carga el contenido en WebView2 directamente desde una cadena. Esto puede ser útil si va a empaquetar el contenido a través del código de la aplicación o si desea crear dinámicamente el contenido.
Otro escenario en el que puede ser útil navegar a una cadena es si desea cargar contenido al que no se puede acceder a través de una dirección URL. Por ejemplo, si tiene una representación en memoria de un documento HTML, podría usar el NavigateToString
método para cargar ese contenido en el control WebView2. Esto puede ser útil si quiere evitar la necesidad de escribir el contenido en un archivo o servidor antes de cargarlo en el control.
Consideraciones para cargar contenido local navegando a una cadena HTML
La cadena de contenido HTML que se pasa al NavigateToString
método tiene un límite de tamaño de 2 MB. Este límite de tamaño puede ser fácil de superar cuando la cadena incluye recursos adicionales incluidos. Si se supera este límite de tamaño, se devuelve un error: "El valor no está dentro del intervalo esperado".
API DOM basadas en origen
Un documento cargado mediante el NavigateToString
método tiene su ubicación establecida en about:blank
y su origen establecido en null
. Esto significa que las API web que dependen de un origen que se está definiendo, como localStorage
o indexedDB
, no se pueden usar.
API dom que requieren contexto seguro
Algunas API web se limitan solo a las direcciones URL HTTPS seguras y no están disponibles para los documentos cargados a través del NavigateToString
método porque su ubicación está establecida en about:blank
. Esto incluye API como navigator.mediaDevices.getUserMedia()
adquirir vídeo o sonido, navigator.geolocation.getCurrentPosition()
acceder a la ubicación del dispositivo o Notification.requestPermission()
solicitar el permiso del usuario para mostrar notificaciones. Consulte Contextos seguros en MDN para obtener más información.
Contenido dinámico
Al cargar contenido local a través del NavigateToString
método , se proporciona directamente el contenido como parámetro al método . Esto significa que tiene el control del contenido en tiempo de ejecución y puede generarlo dinámicamente si es necesario.
Recursos web adicionales
La carga de contenido local mediante el NavigateToString
método no permite que el documento resultante haga referencia a recursos web adicionales, como CSS, imágenes o archivos de script. El método solo permite especificar el contenido de cadena del documento HTML. Para hacer referencia a recursos web adicionales del documento HTML, use uno de los otros enfoques descritos en este artículo o represente esos recursos web adicionales insertados en el documento HTML.
Recursos web adicionales resueltos en el proceso WebView2
NavigateToString
no admite recursos web adicionales, como se mencionó anteriormente.
API para cargar contenido local navegando a una cadena HTML
Representación de cadena de ejemplo de una página web
A continuación se muestra la representación de cadena de la página web Demo To Do . En la lista siguiente se ha agregado ajuste de línea para mejorar la legibilidad. En la práctica, estas líneas se concatenan en una sola línea larga:
`<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 obtener la cadena anterior:
Vaya a Demostración a hacer.
Haga clic con el botón derecho en la página web y seleccione Inspeccionar para abrir DevTools.
En la consola de DevTools, escriba:
document.body.parentElement.outerHTML
. La consola genera una representación de cadena de la página web:
Ejemplo de navegación a una cadena HTML
// Define htmlString with the string representation of HTML as above.
webView.CoreWebView2.NavigateToString(htmlString);
Carga de contenido local mediante la asignación de nombres de host virtual
Otra manera de cargar contenido local en un control WebView2 es usar la asignación de nombres de host virtual. Esto implica la asignación de un nombre de dominio local a una carpeta local, de modo que cuando el control WebView2 intenta cargar un recurso para ese dominio, cargará el contenido desde la ubicación de carpeta local especificada en su lugar. El origen del documento también será el nombre de host virtual.
Este enfoque le permite especificar el acceso entre orígenes mediante la CoreWebView2HostResourceAccessKind
enumeración .
Debido a una limitación actual, los archivos multimedia a los que se accede mediante un nombre de host virtual pueden ser lentos de cargar.
Consideraciones para cargar contenido local mediante la asignación de nombres de host virtual
API DOM basadas en origen
El contenido local cargado a través de la asignación de nombres de host virtual da como resultado un documento que tiene una dirección URL HTTP o HTTPS y un origen correspondiente. Esto significa que las API web que requieren un origen como localStorage
o indexedDB
funcionarán, y otros documentos que pertenecen al mismo origen podrán usar los datos almacenados. Para obtener más información, consulte Directiva del mismo origen en MDN.
API dom que requieren contexto seguro
Algunas API web se limitan solo a las direcciones URL HTTPS seguras. El uso de la asignación de nombres de host virtual proporciona una dirección URL HTTPS para el contenido local. Esto significa que las API como navigator.mediaDevices.getUserMedia()
adquirir vídeo o sonido, navigator.geolocation.getCurrentPosition()
acceder a la ubicación del dispositivo o Notification.requestPermission()
solicitar el permiso del usuario para mostrar notificaciones están disponibles. Consulte Contextos seguros en MDN para obtener más información.
Contenido dinámico
Al cargar contenido local a través de una asignación de nombres de host virtual, se asigna un nombre de host virtual a una carpeta local que contiene archivos estáticos en el disco. Esto significa que no es posible modificar dinámicamente este contenido local. Esto es diferente de cargar documentos desde un servidor web, donde cada respuesta se puede generar dinámicamente.
Recursos web adicionales
El contenido local que se carga a través de la asignación de nombres de host virtual tiene una dirección URL HTTP o HTTPS que admite la resolución relativa de direcciones URL. Esto significa que el documento cargado puede tener referencias a recursos web adicionales, como CSS, scripts o archivos de imagen que también se sirven a través de la asignación de nombres de host virtual.
Recursos web adicionales resueltos en el proceso WebView2
Las direcciones URL del nombre de host virtual se resuelven en los procesos de WebView2. Se trata de una opción más rápida que WebResourceRequested
, que se resuelve en el subproceso de interfaz de usuario del proceso de aplicación host.
API para cargar contenido local mediante la asignación de nombres de host virtual
Ejemplo de asignación de nombres de host virtual
webView.CoreWebView2.SetVirtualHostNameToFolderMapping("demo",
"C:\Github\Demos\demo-to-do", CoreWebView2HostResourceAccessKind.DenyCors);
webView.CoreWebView2.Navigate("https://demo/index.html");
Carga de contenido local mediante el control del evento WebResourceRequested
Otra manera de hospedar contenido local en un control WebView2 es confiar en el WebResourceRequested
evento . Este evento se desencadena cuando el control intenta cargar un recurso. Puede usar este evento para interceptar la solicitud y proporcionar el contenido local, como se describe en Administración personalizada de solicitudes de red.
WebResourceRequested
permite personalizar el comportamiento del contenido local por solicitud. Esto significa que puede decidir para qué solicitudes interceptar y proporcionar su propio contenido y para qué solicitudes permitir que el control WebView2 controle con normalidad. Sin embargo, la personalización del comportamiento requiere más código, como la asignación de host virtual, y requiere conocimientos de HTTP para poder construir una respuesta adecuada.
Desde la perspectiva de WebView2, el recurso habrá venido a través de la red y WebView2 se adhiere a los encabezados que establece la aplicación como parte de la respuesta. El uso del WebResourceRequested
evento también es más lento que otros enfoques, debido a la comunicación y el procesamiento entre procesos necesarios para cada solicitud.
Registro de esquema personalizado
Si desea usar un esquema personalizado para realizar la solicitud de recursos web que genera el WebResourceRequested
evento, consulte Registro de esquemas personalizados en Información general sobre las características y las API de WebView2.
Consideraciones para cargar contenido local controlando el evento WebResourceRequested
API DOM basadas en origen
El contenido local cargado a través de WebResourceRequested
da como resultado un documento que tiene una dirección URL HTTP o HTTPS y un origen correspondiente. Esto significa que las API web que requieren un origen como localStorage
o indexedDB
funcionarán, y otros documentos que pertenecen al mismo origen podrán usar los datos almacenados. Para obtener más información, consulte Directiva del mismo origen en MDN.
API dom que requieren contexto seguro
Algunas API web se limitan solo a las direcciones URL HTTPS seguras. El uso WebResourceRequested
le permite reemplazar las solicitudes de recursos web de dirección URL HTTPS por su propio contenido local. Esto significa que las API como navigator.mediaDevices.getUserMedia()
adquirir vídeo o sonido, navigator.geolocation.getCurrentPosition()
acceder a la ubicación del dispositivo o Notification.requestPermission()
solicitar el permiso del usuario para mostrar notificaciones están disponibles. Consulte Contextos seguros en MDN para obtener más información.
Contenido dinámico
Al cargar contenido local a través de WebResourceRequested
, especifique el contenido local que se va a cargar en el controlador de eventos. Esto significa que tiene el control del contenido en tiempo de ejecución y puede generarlo dinámicamente si es necesario.
Recursos web adicionales
WebResourceRequested
modifica el contenido cargado a través de direcciones URL HTTP o HTTPS, que admiten la resolución relativa de direcciones URL. Esto significa que el documento resultante puede tener referencias a recursos web adicionales, como CSS, scripts o archivos de imagen que también se proporcionan a través de WebResourceRequested
.
Recursos web adicionales resueltos en el proceso WebView2
Al cargar contenido a través de una dirección URL de archivo o una asignación de nombres de host virtual, la resolución se produce en los procesos de WebView2. Sin embargo, el WebResourceRequested
evento se genera en el subproceso de interfaz de usuario WebView2 del proceso de la aplicación host, lo que puede provocar una carga más lenta del documento resultante.
- WebView2 primero pausa la carga de la página web para esperar a que el evento se envíe al proceso de la aplicación host.
- WebView2 espera a que el subproceso de la interfaz de usuario esté disponible.
- WebView2 espera a que el código de la aplicación controle el evento.
Esto puede tardar algún tiempo. Asegúrese de limitar las llamadas a AddWebResourceRequestedFilter
solo los recursos web que deben generar el WebResourceRequested
evento.
API para cargar contenido local controlando el evento WebResourceRequested
Ejemplo de control del 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", "");
}
};
Vea también
- Administración del contenido cargado en WebView2 en Información general sobre las características y las API de WebView2
- Página representada demostración a realizar