Xamarin.Forms WebView

WebView — это представление для отображения веб-содержимого и HTML в приложении:

В браузере приложений

Содержимое

WebView поддерживает следующие типы содержимого:

  • Веб-сайты HTML и CSS — WebView имеет полную поддержку веб-сайтов, написанных с помощью HTML и CSS, включая поддержку JavaScript.
  • Документы. Так как WebView реализуется с помощью собственных компонентов на каждой платформе, WebView может отображать документы в форматах, поддерживаемых базовой платформой.
  • СТРОКИ HTML — WebView может отображать HTML-строки из памяти.
  • Локальные файлы — WebView может представить любой из типов контента, указанных выше, внедренных в приложение.

Примечание.

WebView В Windows не поддерживается Silverlight, Flash или какие-либо элементы ActiveX, даже если они поддерживаются Internet Explorer на этой платформе.

Веб-сайты

Чтобы отобразить веб-сайт из Интернета, задайте WebViewSource для свойства строковый URL-адрес:

var browser = new WebView
{
  Source = "https://dotnet.microsoft.com/apps/xamarin"
};

Примечание.

URL-адреса должны быть полностью сформированы с указанным протоколом (т. е. он должен иметь "http://" или "https://" предварительно добавлен к нему).

iOS и ATS

С версии 9 iOS позволит приложению взаимодействовать только с серверами, реализующими оптимальную безопасность по умолчанию. Значения должны быть заданы для Info.plist включения связи с небезопасными серверами.

Примечание.

Если приложению требуется подключение к небезопасным веб-сайту, всегда следует ввести домен в качестве исключения, используя NSExceptionDomains вместо того, чтобы полностью отключить NSAllowsArbitraryLoadsATS. NSAllowsArbitraryLoads следует использовать только в чрезвычайных ситуациях.

Ниже показано, как включить определенный домен (в данном случае xamarin.com) для обхода требований 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>

Рекомендуется использовать только некоторые домены для обхода ATS, что позволяет использовать доверенные сайты, используя дополнительные возможности безопасности для ненадежных доменов. Ниже показан менее безопасный метод отключения ATS для приложения:

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads </key>
        <true/>
    </dict>
    ...
</key>

Дополнительные сведения об этой новой функции в iOS 9 см. в статье "Безопасность транспорта приложений".

СТРОКИ HTML

Если вы хотите представить строку HTML, определяемую динамически в коде, необходимо создать экземпляр 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;

Веб-представление, отображающее HTML-строку

В приведенном выше коде @ используется для маркировки HTML как строкового литерала подробной строки, что означает, что большинство escape-символов игнорируются.

Примечание.

Может потребоваться задать WidthRequest и HeightRequest свойства для просмотра HTML-содержимого WebView в зависимости от макета WebView , который является дочерним. Например, это необходимо в объекте StackLayout.

Локальное HTML-содержимое

WebView может отображать содержимое из HTML, CSS и JavaScript, внедренных в приложение. Например:

<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;
}

Обратите внимание, что шрифты, указанные в приведенном выше CSS, необходимо настроить для каждой платформы, так как не каждая платформа имеет одинаковые шрифты.

Чтобы отобразить локальное содержимое с помощью, WebViewнеобходимо открыть HTML-файл, как и любой другой, а затем загрузить содержимое в виде строки в Html свойство объекта HtmlWebViewSource. Дополнительные сведения об открытии файлов см. в разделе "Работа с файлами".

На следующих снимках экрана показан результат отображения локального содержимого на каждой платформе:

Веб-представление, отображающее локальное содержимое

Хотя первая страница была загружена, у него нет знаний о том, WebView откуда пришел HTML-код. Это проблема при работе со страницами, ссылающимися на локальные ресурсы. Примеры того, когда это может произойти, если локальные страницы связаны друг с другом, страница использует отдельный файл JavaScript или ссылки страницы на таблицу стилей CSS.

Чтобы решить эту проблему, необходимо указать, WebView где найти файлы в файловой системе. Сделайте это, задав BaseUrl свойство, используемое HtmlWebViewSource параметром WebView.

Так как файловая система на каждой из операционных систем отличается, необходимо определить этот URL-адрес на каждой платформе. Xamarin.Forms предоставляет DependencyService разрешение зависимостей во время выполнения на каждой платформе.

Для использования DependencyServiceсначала определите интерфейс, который можно реализовать на каждой платформе:

public interface IBaseUrl { string Get(); }

Обратите внимание, что до реализации интерфейса на каждой платформе приложение не будет выполняться. В общем проекте убедитесь, что не забудьте задать параметр BaseUrl :DependencyService

var source = new HtmlWebViewSource();
source.BaseUrl = DependencyService.Get<IBaseUrl>().Get();

Затем необходимо предоставить реализации интерфейса для каждой платформы.

iOS

В iOS веб-содержимое должно находиться в корневом каталоге проекта или каталоге ресурсов с действием сборки BundleResource, как показано ниже:

Необходимо BaseUrl задать путь к основному пакету:

[assembly: Dependency (typeof (BaseUrl_iOS))]
namespace WorkingWithWebview.iOS
{
  public class BaseUrl_iOS : IBaseUrl
  {
    public string Get()
    {
      return NSBundle.MainBundle.BundlePath;
    }
  }
}

Android

В Android поместите HTML, CSS и изображения в папку "Активы" с действием сборки AndroidAsset , как показано ниже:

В Android BaseUrl должно быть задано значение "file:///android_asset/":

[assembly: Dependency (typeof(BaseUrl_Android))]
namespace WorkingWithWebview.Android
{
  public class BaseUrl_Android : IBaseUrl
  {
    public string Get()
    {
      return "file:///android_asset/";
    }
  }
}

В Android файлы в папке "Активы" также можно получить через текущий контекст Android, который предоставляется свойством MainActivity.Instance :

var assetManager = MainActivity.Instance.Assets;
using (var streamReader = new StreamReader (assetManager.Open ("local.html")))
{
  var html = streamReader.ReadToEnd ();
}

Универсальная платформа Windows

В проектах универсальная платформа Windows (UWP) поместите HTML, CSS и изображения в корневой каталог проекта с заданным действием сборки контентом.

Должно BaseUrl быть задано значение "ms-appx-web:///":

[assembly: Dependency(typeof(BaseUrl))]
namespace WorkingWithWebview.UWP
{
    public class BaseUrl : IBaseUrl
    {
        public string Get()
        {
            return "ms-appx-web:///";
        }
    }
}

WebView поддерживает навигацию по нескольким методам и свойствам, которые она делает доступной:

  • GoForward() — если CanGoForward имеет значение true, вызов GoForward переходит к следующей посещенной странице.
  • GoBack() — если CanGoBack имеет значение true, вызов GoBack перейдет на последнюю просматриваемую страницу.
  • CanGoBacktrue если есть страницы для перехода обратно, false если браузер находится в начальном URL-адресе.
  • CanGoForwardtrue если пользователь перешел назад и может перейти на страницу, которую уже посетили.

На страницах WebView не поддерживает жесты с несколькими сенсорными жестами. Важно убедиться, что содержимое оптимизировано для мобильных устройств и отображается без необходимости масштабирования.

Обычно приложения могут отображать ссылку в браузере WebView, а не в браузере устройства. В таких ситуациях полезно разрешить обычную навигацию, но когда пользователь попадает обратно, пока они находятся на начальной ссылке, приложение должно вернуться в обычное представление приложения.

Используйте встроенные методы навигации и свойства, чтобы включить этот сценарий.

Начните с создания страницы для представления браузера:

<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>

В коде программной части:

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();
        }
    }
}

Вот и все!

Кнопки навигации WebView

События

WebView создает следующие события, которые помогут вам реагировать на изменения в состоянии:

  • Navigating — событие, возникаемое при начале загрузки новой страницы WebView.
  • Navigated — событие, возникаемое при загрузке страницы и остановке навигации.
  • ReloadRequested — событие, возникает при выполнении запроса на перезагрузку текущего содержимого.

Объект WebNavigatingEventArgs , сопровождающий Navigating событие, имеет четыре свойства:

  • Cancel — указывает, следует ли отменять навигацию.
  • NavigationEvent — событие навигации, которое было создано.
  • Source — элемент, выполняющий навигацию.
  • Url — назначение навигации.

Объект WebNavigatedEventArgs , сопровождающий Navigated событие, имеет четыре свойства:

  • NavigationEvent — событие навигации, которое было создано.
  • Result — описывает результат навигации с помощью WebNavigationResult элемента перечисления. Допустимые значения: Cancel, Failure, Success и Timeout.
  • Source — элемент, выполняющий навигацию.
  • Url — назначение навигации.

Если вы планируете использовать веб-страницы, которые занимают много времени для загрузки, рассмотрите возможность использования Navigating и Navigated событий для реализации индикатора состояния. Например:

<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>

Два обработчика событий:

void webviewNavigating(object sender, WebNavigatingEventArgs e)
{
    labelLoading.IsVisible = true;
}

void webviewNavigated(object sender, WebNavigatedEventArgs e)
{
    labelLoading.IsVisible = false;
}

Это приводит к следующим выходным данным (загрузка):

Снимок экрана: событие навигации WebView при загрузке.

Завершенная загрузка:

Снимок экрана: событие навигации WebView после загрузки.

Перезагрузить содержимое

WebViewReload имеет метод, который можно использовать для перезагрузки текущего содержимого:

var webView = new WebView();
...
webView.Reload();

Reload При вызове ReloadRequested метода событие указывает, что запрос был выполнен для перезагрузки текущего содержимого.

Производительность

Популярные веб-браузеры применяют такие технологии, как аппаратное ускорение отрисовки и компиляция JavaScript. Xamarin.Forms До 4.4 он Xamarin.FormsWebView был реализован в iOS классомUIWebView. Однако многие из этих технологий были недоступны в этой реализации. Поэтому, начиная с Xamarin.Forms версии 4.4, он Xamarin.FormsWebView реализуется в iOS классом, который поддерживает более быстрый WkWebView просмотр.

Примечание.

В iOS WkWebViewRenderer имеет перегрузку конструктора, принимающую WkWebViewConfiguration аргумент. Это позволяет отрисовщику настраиваться при создании.

Приложение может вернуться к использованию класса iOS UIWebView для реализации Xamarin.FormsWebViewпо соображениям совместимости. Это можно сделать, добавив следующий код в файл AssemblyInfo.cs в проекте платформы iOS для приложения:

// Opt-in to using UIWebView instead of WkWebView.
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(Xamarin.Forms.Platform.iOS.WebViewRenderer))]

Примечание.

В Xamarin.Forms версии 5.0 WebViewRenderer класс был удален. Xamarin.Forms Поэтому 5.0 не содержит ссылку на UIWebView элемент управления.

WebView По умолчанию в Android используется примерно так же быстро, как встроенный браузер.

В Веб-представлении UWP используется модуль отрисовки Microsoft Edge. Устройства с настольными компьютерами и планшетами должны видеть ту же производительность, что и сам браузер Edge.

Разрешения

Чтобы WebView обеспечить работу, необходимо убедиться, что для каждой платформы заданы разрешения. Обратите внимание, WebView что на некоторых платформах будут работать в режиме отладки, но не при создании для выпуска. Это связано с тем, что некоторые разрешения, например для доступа к Интернету в Android, задаются по умолчанию Visual Studio для Mac в режиме отладки.

  • UWP — требует возможности Интернета (клиента и сервера) при отображении сетевого содержимого.
  • Android — требуется INTERNET только при отображении содержимого из сети. Локальное содержимое не требует специальных разрешений.
  • iOS — не требует специальных разрешений.

Макет

В отличие от большинства других Xamarin.Forms представлений, WebView требуется, чтобы HeightRequest они WidthRequest были указаны в StackLayout или RelativeLayout. Если не указать эти свойства, он WebView не будет отображаться.

В следующих примерах показаны макеты, которые приводят к работе, отрисовке WebView:

StackLayout с WidthRequest и HeightRequest:

<StackLayout>
    <Label Text="test" />
    <WebView Source="https://dotnet.microsoft.com/apps/xamarin"
        HeightRequest="1000"
        WidthRequest="1000" />
</StackLayout>

RelativeLayout с 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 без 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>

Сетка без WidthRequest и HeightRequest. Сетка является одним из немногих макетов, которые не требуют указания запрошенных высот и ширин.:

<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>

Вызов JavaScript

WebView включает возможность вызывать функцию JavaScript из C#и возвращать любой результат вызывающей коду C#. Это выполняется с помощью метода 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}.";

Метод WebView.EvaluateJavaScriptAsync вычисляет JavaScript, указанный в качестве аргумента, и возвращает любой результат в виде string. В этом примере factorial вызывается функция JavaScript, которая возвращает факториал number в результате. Эта функция JavaScript определена в локальном HTML-файле, который WebView загружается и показан в следующем примере:

<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>

Файлы cookie

Файлы cookie можно задать в объекте WebView, который затем отправляется с веб-запросом на указанный URL-адрес. Это достигается путем добавления Cookie объектов в объект CookieContainer, который затем устанавливается в качестве значения WebView.Cookies привязываемого свойства. В приведенном ниже коде показан соответствующий пример:

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() };

В этом примере один Cookie добавляется в CookieContainer объект, который затем задается в качестве значения WebView.Cookies свойства. WebView Когда веб-запрос отправляется в указанный URL-адрес, файл cookie отправляется с запросом.

Отклонение UIWebView и отклонение Магазина приложений (ITMS-90809)

Начиная с апреля 2020 года Apple отклонит приложения , которые по-прежнему используют устаревший UIWebView API. Хотя Xamarin.Forms переключился WKWebView в качестве значения по умолчанию, в двоичных Xamarin.Forms файлах по-прежнему существует ссылка на старый пакет SDK. Текущее поведение компоновщика iOS не удаляет это, и в результате UIWebView устаревший API по-прежнему будет ссылаться из приложения при отправке в App Store.

Внимание

В Xamarin.Forms версии 5.0 WebViewRenderer класс был удален. Xamarin.Forms Поэтому 5.0 не содержит ссылку на UIWebView элемент управления.

Предварительная версия компоновщика доступна для устранения этой проблемы. Чтобы включить предварительную версию, необходимо указать дополнительный аргумент --optimize=experimental-xforms-product-type компоновщику.

Необходимые условия для работы:

  • Xamarin.Forms 4.5 или более поздней версии. Xamarin.Forms 4.6 или более поздней версии требуется, если приложение использует визуальный элемент Материал.
  • Xamarin.iOS 13.10.0.17 или более поздней версии. Проверьте версию Xamarin.iOS в Visual Studio. Эта версия Xamarin.iOS входит в состав Visual Studio для Mac 8.4.1 и Visual Studio 16.4.3.
  • Удаление ссылок на UIWebView. Код не должен содержать ссылки на UIWebView классы, которые используются UIWebView.

Дополнительные сведения об обнаружении и удалении UIWebView ссылок см. в разделе О прекращении использования UIWebView.

Настройка компоновщика

Выполните следующие действия, чтобы компоновщик удалил UIWebView ссылки:

  1. Откройте свойства проекта iOS— щелкните правой кнопкой мыши проект iOS и выберите "Свойства".
  2. Перейдите к разделу "Сборка iOS" — выберите раздел "Сборка iOS".
  3. Обновите дополнительные аргументы mtouch. В дополнительных аргументах mtouch добавьте этот флаг --optimize=experimental-xforms-product-type (в дополнение к любому значению, которое уже может быть в нем). Примечание. Этот флаг работает вместе с поведением компоновщика, установленным только для пакета SDK или связывания всех. Если по какой-либо причине при настройке поведения компоновщика для всех возникают ошибки, это, скорее всего, проблема в коде приложения или сторонней библиотеке, которая не является компоновщиком безопасной. Дополнительные сведения о компоновщике см. в разделе "Связывание приложений Xamarin.iOS".
  4. Обновите все конфигурации сборки— используйте списки конфигураций и платформы в верхней части окна, чтобы обновить все конфигурации сборки. Наиболее важной конфигурацией является конфигурация выпуска и iPhone , так как она обычно используется для создания сборок для отправки App Store.

Окно отображается с новым флагом на этом снимке экрана:

Настройка флага в разделе

Теперь при создании сборки (выпуска) и отправке ее в App Store не должно быть предупреждений об устаревшем API.