Xamarin.Forms Vista web
WebView
es una vista para mostrar contenido web y HTML en la aplicación:
Contenido
WebView
admite los siguientes tipos de contenido:
- Sitios web HTML y CSS: WebView tiene compatibilidad completa con sitios web escritos mediante HTML y CSS, incluida la compatibilidad con JavaScript.
- Documentos: dado que WebView se implementa mediante componentes nativos en cada plataforma, WebView es capaz de mostrar documentos en los formatos compatibles con la plataforma subyacente.
- Cadenas HTML: WebView puede mostrar cadenas HTML de la memoria.
- Archivos locales: WebView puede presentar cualquiera de los tipos de contenido anteriores insertados en la aplicación.
Nota:
WebView
en Windows no admite Silverlight, Flash ni ningún control ActiveX, incluso si son compatibles con Internet Explorer en esa plataforma.
Sitios web
Para mostrar un sitio web de Internet, establezca la propiedad WebView
de Source
en una cadena URL:
var browser = new WebView
{
Source = "https://dotnet.microsoft.com/apps/xamarin"
};
Nota:
Las direcciones URL deben estar totalmente formadas con el protocolo especificado (es decir, debe tener "http://" o "https://" antepuestos a él).
iOS y ATS
Desde la versión 9, iOS solo permitirá que la aplicación se comunique con los servidores que implementan la seguridad de procedimientos recomendados de forma predeterminada. Los valores deben establecerse en Info.plist
para habilitar la comunicación con servidores no seguros.
Nota:
Si la aplicación requiere una conexión a un sitio web no seguro, siempre debe escribir el dominio como una excepción mediante NSExceptionDomains
en lugar de desactivar ATS completamente mediante NSAllowsArbitraryLoads
. NSAllowsArbitraryLoads
solo debe utilizarse en situaciones de emergencia extremas.
A continuación se muestra cómo habilitar un dominio específico (en este caso xamarin.com) para omitir los requisitos de ATS:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>xamarin.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
...
</key>
Se recomienda habilitar solo algunos dominios para omitir ATS, lo que le permite usar sitios de confianza mientras se beneficia de la seguridad adicional en dominios que no son de confianza. A continuación se muestra el método menos seguro para deshabilitar ATS para la aplicación:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads </key>
<true/>
</dict>
...
</key>
Consulte Seguridad de transporte de aplicaciones para obtener más información sobre esta nueva característica en iOS 9.
Cadenas HTML
Si desea presentar una cadena de HTML definida dinámicamente en el código, deberá crear una instancia de HtmlWebViewSource
:
var browser = new WebView();
var htmlSource = new HtmlWebViewSource();
htmlSource.Html = @"<html><body>
<h1>Xamarin.Forms</h1>
<p>Welcome to WebView.</p>
</body></html>";
browser.Source = htmlSource;
En el código anterior, @
se usa para marcar el HTML como literal de cadena textual, lo que significa que la mayoría de los caracteres de escape se omiten.
Nota:
Puede ser necesario establecer las propiedades WidthRequest
y HeightRequest
de WebView
para ver el contenido HTML, dependiendo del diseño del elemento WebView
secundario. Por ejemplo, esto es necesario en StackLayout
.
Contenido HTML local
WebView puede mostrar contenido de HTML, CSS y JavaScript insertados en la aplicación. Por ejemplo:
<html>
<head>
<title>Xamarin Forms</title>
</head>
<body>
<h1>Xamarin.Forms</h1>
<p>This is an iOS web page.</p>
<img src="XamarinLogo.png" />
</body>
</html>
CSS:
html,body {
margin:0;
padding:10;
}
body,p,h1 {
font-family: Chalkduster;
}
Tenga en cuenta que las fuentes especificadas en el CSS anterior deben personalizarse para cada plataforma, ya que no todas las plataformas tienen las mismas fuentes.
Para mostrar el contenido local mediante WebView
, deberá abrir el archivo HTML como cualquier otro y, a continuación, cargar el contenido como una cadena en la propiedad Html
de HtmlWebViewSource
. Para obtener más información sobre cómo abrir archivos, vea Trabajar con archivos.
Las capturas de pantalla siguientes muestran el resultado de mostrar contenido local en cada plataforma:
Aunque se ha cargado la primera página, WebView
no tiene conocimiento de dónde procede el código HTML. Se trata de un problema al tratar con páginas que hacen referencia a recursos locales. Algunos ejemplos de cuándo puede ocurrir incluyen cuando las páginas locales se vinculan entre sí, una página usa un archivo JavaScript independiente o un vínculo de página a una hoja de estilos CSS.
Para solucionar esto, debe decirle al WebView
dónde encontrar los archivos en el sistema de archivos. Para ello, establezca la propiedad BaseUrl
en HtmlWebViewSource
utilizada por WebView
.
Dado que el sistema de archivos de cada uno de los sistemas operativos es diferente, debe determinar esa dirección URL en cada plataforma. Xamarin.Forms expone DependencyService
para resolver las dependencias en tiempo de ejecución en cada plataforma.
Para usar DependencyService
, defina primero una interfaz que pueda implementarse en cada plataforma:
public interface IBaseUrl { string Get(); }
Tenga en cuenta que hasta que la interfaz se implemente en cada plataforma, la aplicación no se ejecutará. En el proyecto común, asegúrese de que recuerda establecer BaseUrl
utilizando DependencyService
:
var source = new HtmlWebViewSource();
source.BaseUrl = DependencyService.Get<IBaseUrl>().Get();
Las implementaciones de la interfaz para cada plataforma deben proporcionarse.
iOS
En iOS, el contenido web debe ubicarse en el directorio raíz del proyecto o en el directorio Resources con la acción de compilación BundleResource, como se demuestra a continuación:
El BaseUrl
debe ajustarse a la ruta del paquete principal:
[assembly: Dependency (typeof (BaseUrl_iOS))]
namespace WorkingWithWebview.iOS
{
public class BaseUrl_iOS : IBaseUrl
{
public string Get()
{
return NSBundle.MainBundle.BundlePath;
}
}
}
Android
En Android, coloque el HTML, el CSS y las imágenes en la carpeta Assets con la acción de compilación AndroidAsset como se demuestra a continuación:
En Android, el BaseUrl
debe establecerse en "file:///android_asset/"
:
[assembly: Dependency (typeof(BaseUrl_Android))]
namespace WorkingWithWebview.Android
{
public class BaseUrl_Android : IBaseUrl
{
public string Get()
{
return "file:///android_asset/";
}
}
}
En Android, también se puede acceder a los archivos de la carpeta Assets a través del contexto actual de Android, que se expone mediante la propiedad MainActivity.Instance
:
var assetManager = MainActivity.Instance.Assets;
using (var streamReader = new StreamReader (assetManager.Open ("local.html")))
{
var html = streamReader.ReadToEnd ();
}
Plataforma universal de Windows
En los proyectos de la plataforma universal de Windows (UWP), coloque HTML, CSS e imágenes en la raíz del proyecto con la acción de compilación establecida en Content.
BaseUrl
debe establecerse en "ms-appx-web:///"
:
[assembly: Dependency(typeof(BaseUrl))]
namespace WorkingWithWebview.UWP
{
public class BaseUrl : IBaseUrl
{
public string Get()
{
return "ms-appx-web:///";
}
}
}
Navegación
WebView admite la navegación a través de varios métodos y propiedades que pone a disposición:
- GoForward(): si
CanGoForward
es true, al llamar aGoForward
se desplaza hacia adelante a la siguiente página visitada. - GoBack(): si
CanGoBack
es true, al llamar aGoBack
se desplazará a la última página visitada. - CanGoBack:
true
si hay páginas a las que volver,false
si el navegador se encuentra en la URL inicial. - CanGoForward:
true
si el usuario se ha desplazado hacia atrás y puede avanzar a una página ya visitada.
Dentro de las páginas, WebView
no admite gestos multitáctil. Es importante asegurarse de que el contenido está optimizado para dispositivos móviles y que aparece sin necesidad de hacer zoom.
Es habitual que las aplicaciones muestren un enlace dentro de un WebView
, en lugar del navegador del dispositivo. En esas situaciones, resulta útil permitir la navegación normal, pero cuando el usuario vuelve mientras se encuentra en el vínculo de inicio, la aplicación debe volver a la vista de la aplicación normal.
Use los métodos y propiedades de navegación integrados para habilitar este escenario.
Empiece por crear la página para la vista del explorador:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebViewSample.InAppBrowserXaml"
Title="Browser">
<StackLayout Margin="20">
<StackLayout Orientation="Horizontal">
<Button Text="Back" HorizontalOptions="StartAndExpand" Clicked="OnBackButtonClicked" />
<Button Text="Forward" HorizontalOptions="EndAndExpand" Clicked="OnForwardButtonClicked" />
</StackLayout>
<!-- WebView needs to be given height and width request within layouts to render. -->
<WebView x:Name="webView" WidthRequest="1000" HeightRequest="1000" />
</StackLayout>
</ContentPage>
En el código subyacente:
public partial class InAppBrowserXaml : ContentPage
{
public InAppBrowserXaml(string URL)
{
InitializeComponent();
webView.Source = URL;
}
async void OnBackButtonClicked(object sender, EventArgs e)
{
if (webView.CanGoBack)
{
webView.GoBack();
}
else
{
await Navigation.PopAsync();
}
}
void OnForwardButtonClicked(object sender, EventArgs e)
{
if (webView.CanGoForward)
{
webView.GoForward();
}
}
}
Eso es todo.
Eventos
WebView genera los siguientes eventos para ayudarle a responder a los cambios en el estado:
Navigating
: evento generado cuando WebView comienza a cargar una nueva página.Navigated
: evento generado cuando se carga la página y la navegación se ha detenido.ReloadRequested
: evento generado cuando se realiza una solicitud para volver a cargar el contenido actual.
El objeto WebNavigatingEventArgs
que acompaña al evento Navigating
tiene cuatro propiedades:
Cancel
: indica si se va a cancelar o no la navegación.NavigationEvent
: evento de navegación que se ha generado.Source
: obtiene el elemento que ha realizado la navegación.Url
: el destino de navegación.
El objeto WebNavigatedEventArgs
que acompaña al evento Navigated
tiene cuatro propiedades:
NavigationEvent
: evento de navegación que se ha generado.Result
: describe el resultado de la navegación mediante un miembro de enumeraciónWebNavigationResult
. Los valores válidos sonCancel
,Failure
,Success
yTimeout
.Source
: obtiene el elemento que ha realizado la navegación.Url
: el destino de navegación.
Si prevé usar páginas web que tardan mucho tiempo en cargarse, considere la posibilidad de usar los eventos Navigating
y Navigated
para implementar un indicador de estado. Por ejemplo:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebViewSample.LoadingLabelXaml"
Title="Loading Demo">
<StackLayout>
<!--Loading label should not render by default.-->
<Label x:Name="labelLoading" Text="Loading..." IsVisible="false" />
<WebView HeightRequest="1000" WidthRequest="1000" Source="https://dotnet.microsoft.com/apps/xamarin" Navigated="webviewNavigated" Navigating="webviewNavigating" />
</StackLayout>
</ContentPage>
Los dos controladores de eventos:
void webviewNavigating(object sender, WebNavigatingEventArgs e)
{
labelLoading.IsVisible = true;
}
void webviewNavigated(object sender, WebNavigatedEventArgs e)
{
labelLoading.IsVisible = false;
}
Esto da como resultado la siguiente salida (carga):
Carga finalizada:
Recarga de contenido
WebView
tiene un método Reload
que se puede usar para volver a cargar el contenido actual:
var webView = new WebView();
...
webView.Reload();
Cuando se invoca el método Reload
, se desencadena el evento ReloadRequested
, lo que indica que se ha realizado una solicitud para recargar el contenido actual.
Rendimiento
Los exploradores web populares adoptan tecnologías como la representación acelerada por hardware y la compilación de JavaScript. Antes de Xamarin.Forms 4.4, Xamarin.FormsWebView
se implementaba en iOS mediante la clase UIWebView
. Sin embargo, muchas de estas tecnologías no estaban disponibles en esta implementación. Por lo tanto, desde Xamarin.Forms 4.4, Xamarin.FormsWebView
se implementa en iOS mediante la clase WkWebView
, que permite una navegación más rápida.
Nota:
En iOS, WkWebViewRenderer
tiene una sobrecarga de constructor que acepta un argumento WkWebViewConfiguration
. Esto permite configurar el representador al crearlo.
Una aplicación puede volver a utilizar la clase UIWebView
de iOS para implementar Xamarin.FormsWebView
, por razones de compatibilidad. Esto se puede lograr agregando el código siguiente al archivo AssemblyInfo.cs en el proyecto de la plataforma iOS para la aplicación:
// Opt-in to using UIWebView instead of WkWebView.
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(Xamarin.Forms.Platform.iOS.WebViewRenderer))]
Nota:
En Xamarin.Forms 5.0, se ha quitado la clase WebViewRenderer
. Por lo tanto, Xamarin.Forms 5.0 no contiene una referencia al control UIWebView
.
WebView
en Android de forma predeterminada es tan rápido como el explorador integrado.
La vista web de UWP usa el motor de representación de Microsoft Edge. Los dispositivos de escritorio y tableta deben ver el mismo rendimiento que el uso del propio explorador Edge.
Permisos
Para que WebView
funcione, debe asegurarse de que los permisos están establecidos para cada plataforma. Tenga en cuenta que en algunas plataformas funcionará WebView
en modo de depuración, pero no cuando se compila para la versión. Esto se debe a que algunos permisos, como los de acceso a Internet en Android, se establecen de forma predeterminada por Visual Studio para Mac cuando están en modo de depuración.
- UWP: requiere la funcionalidad internet (cliente y servidor) al mostrar contenido de red.
- Android: solo requiere
INTERNET
al mostrar contenido de la red. El contenido local no requiere permisos especiales. - iOS: no requiere permisos especiales.
Layout
A diferencia de la mayoría de las otras vistas Xamarin.Forms, WebView
requiere que se especifiquen HeightRequest
y WidthRequest
cuando está contenida en StackLayout o RelativeLayout. Si no especifica esas propiedades, WebView
no se representará.
Los siguientes ejemplos demuestran disposiciones que dan como resultado WebView
s que funcionan y se renderizan:
StackLayout con WidthRequest & HeightRequest:
<StackLayout>
<Label Text="test" />
<WebView Source="https://dotnet.microsoft.com/apps/xamarin"
HeightRequest="1000"
WidthRequest="1000" />
</StackLayout>
RelativeLayout con WidthRequest & HeightRequest:
<RelativeLayout>
<Label Text="test"
RelativeLayout.XConstraint= "{ConstraintExpression
Type=Constant, Constant=10}"
RelativeLayout.YConstraint= "{ConstraintExpression
Type=Constant, Constant=20}" />
<WebView Source="https://dotnet.microsoft.com/apps/xamarin"
RelativeLayout.XConstraint="{ConstraintExpression Type=Constant,
Constant=10}"
RelativeLayout.YConstraint="{ConstraintExpression Type=Constant,
Constant=50}"
WidthRequest="1000" HeightRequest="1000" />
</RelativeLayout>
AbsoluteLayout sin WidthRequest & HeightRequest:
<AbsoluteLayout>
<Label Text="test" AbsoluteLayout.LayoutBounds="0,0,100,100" />
<WebView Source="https://dotnet.microsoft.com/apps/xamarin"
AbsoluteLayout.LayoutBounds="0,150,500,500" />
</AbsoluteLayout>
Cuadrícula sin WidthRequest & HeightRequest. La cuadrícula es uno de los pocos diseños que no requiere especificar las alturas y anchuras solicitadas.:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Text="test" Grid.Row="0" />
<WebView Source="https://dotnet.microsoft.com/apps/xamarin" Grid.Row="1" />
</Grid>
Invocación de JavaScript
WebView
incluye la capacidad de invocar una función JavaScript desde C#, y devolver cualquier resultado al código C# que realiza la llamada. Esto se realiza mediante el método WebView.EvaluateJavaScriptAsync
:
var numberEntry = new Entry { Text = "5" };
var resultLabel = new Label();
var webView = new WebView();
...
int number = int.Parse(numberEntry.Text);
string result = await webView.EvaluateJavaScriptAsync($"factorial({number})");
resultLabel.Text = $"Factorial of {number} is {result}.";
El método WebView.EvaluateJavaScriptAsync
evalúa el JavaScript especificado como argumento y devuelve cualquier resultado como string
. En este ejemplo, se invoca la función factorial
de JavaScript, que devuelve el factorial de number
como resultado. Esta función de JavaScript se define en el archivo HTML local que carga WebView
y se muestra en el ejemplo siguiente:
<html>
<body>
<script type="text/javascript">
function factorial(num) {
if (num === 0 || num === 1)
return 1;
for (var i = num - 1; i >= 1; i--) {
num *= i;
}
return num;
}
</script>
</body>
</html>
Cookies
Se pueden establecer cookies en un WebView
, que luego se envían con la solicitud web a la URL especificada. Esto se consigue agregando objetos Cookie
a un CookieContainer
, que luego se establece como valor de la propiedad enlazable WebView.Cookies
. El código siguiente muestra un ejemplo de esto:
using System.Net;
using Xamarin.Forms;
// ...
CookieContainer cookieContainer = new CookieContainer();
Uri uri = new Uri("https://dotnet.microsoft.com/apps/xamarin", UriKind.RelativeOrAbsolute);
Cookie cookie = new Cookie
{
Name = "XamarinCookie",
Expires = DateTime.Now.AddDays(1),
Value = "My cookie",
Domain = uri.Host,
Path = "/"
};
cookieContainer.Add(uri, cookie);
webView.Cookies = cookieContainer;
webView.Source = new UrlWebViewSource { Url = uri.ToString() };
En este ejemplo, se agrega un único Cookie
al objeto CookieContainer
, que luego se establece como el valor de la propiedad WebView.Cookies
. Cuando WebView
envía una solicitud web a la dirección URL especificada, la cookie se envía con la solicitud.
Depreciación de UIWebView y rechazo de la App Store (ITMS-90809)
A partir de abril de 2020, Apple rechazará las apps que sigan utilizando la obsoleta API UIWebView
. Aunque Xamarin.Forms ha cambiado a WKWebView
como valor predeterminado, todavía existe una referencia al SDK más antiguo en los archivos binarios Xamarin.Forms. El comportamiento actual del enlazador iOS no elimina esto, y como resultado la obsoleta API UIWebView
seguirá apareciendo como referenciada desde su aplicación cuando la envíe a la App Store.
Importante
En Xamarin.Forms 5.0, se ha quitado la clase WebViewRenderer
. Por lo tanto, Xamarin.Forms 5.0 no contiene una referencia al control UIWebView
.
Hay disponible una versión preliminar del enlazador para corregir este problema. Para activar la versión preliminar, deberá proporcionar un argumento adicional --optimize=experimental-xforms-product-type
al enlazador.
Los requisitos para que esto funcione son:
- Xamarin.Forms 4.5 o versiones posteriores. Xamarin.Forms 4.6, o versiones posteriores, es necesario si la aplicación usa Material Visual.
- Xamarin.iOS 13.10.0.17 o versiones posteriores. Compruebe la versión de Xamarin.iOS en Visual Studio. Esta versión de Xamarin.iOS se incluye con Visual Studio para Mac 8.4.1 y Visual Studio 16.4.3.
- Se eliminan referencias a
UIWebView
. El código no debe tener referencias aUIWebView
ni a ninguna clase que useUIWebView
.
Para obtener más información sobre cómo detectar y quitar referencias UIWebView
, vea Desuso de UIWebView.
Configurar el enlazador
Siga estos pasos para que el enlazador quite las referencias UIWebView
:
- Abra las propiedades del proyecto de iOS: haga clic con el botón derecho en el proyecto de iOS y elija Propiedades.
- Vaya a la sección Compilación de iOS: seleccione la sección Compilación de iOS.
- Actualización de los argumentos mtouch adicionales: en los Argumentos mtouch adicionales agregue esta marca
--optimize=experimental-xforms-product-type
(además de cualquier valor que ya pudiera estar ahí). Nota: esta marca funciona junto con el comportamiento del enlazador establecido en SDK Only o Link All. Si, por cualquier motivo, ve errores al establecer el comportamiento del enlazador en All, es más probable que se produzca un problema en el código de la aplicación o en una biblioteca de terceros que no sea segura del enlazador. Para obtener más información sobre el enlazador, consulte Vinculación de aplicaciones de Xamarin.iOS. - Actualizar todas las configuraciones de compilación: use las listas configuración y plataforma en la parte superior de la ventana para actualizar todas las configuraciones de compilación. La configuración más importante que hay que actualizar es la de Release/iPhone, ya que es la que se suele utilizar para crear compilaciones para el envío a la App Store.
Puede ver la ventana con la nueva marca en su lugar en esta captura de pantalla:
Ahora, al crear una nueva compilación (versión) y enviarla a App Store, no debería haber advertencias sobre la API en desuso.