Объединение приложений и веб-сайтов с помощью HTML x-ms-webview

x-ms-webview — это мощный элемент управления, позволяющий встраивать веб-содержимое прямо в пользовательский интерфейс приложения. Этот элемент был доступен XAML-приложениям Магазина Windows начиная с версии Windows 8. В Windows 8.1 мы представили много всяческих обновлений, о которых можно прочитать в статье Сэма Спенсера «Что нового в WebView в Windows 8.1». Как сказано в статье Сэма, одно из крупнейших обновлений — то, что данный элемент управления теперь доступен для приложений, написанных на HTML и JavaScript!

Если вы разработчик приложений на HTML/JS, то x-ms-webview — прекрасный способ добавить в них веб-содержимое. В данной статье мы рассмотрим причины, почему вам захочется обновить свои приложения для использования x-ms-webview. Кроме того, я дам несколько рекомендаций касательно того, как воспользоваться всеми возможностями x-ms-webview.

Зачем мы создали HTML x-ms-webview?

Когда я разговариваю с HTML-разработчиками о новом элементе управления x-ms-webview, их первая реакция обычно такая: «Зачем мне это нужно?» Приложения на JavaScript имеют возможность размещать веб-контент в элементе iframe, так что это хороший вопрос. Но фреймы iframe имеют несколько ограничений, из-за которых встраивание веб-содержимого становится трудоемким, а в некоторых случаях — невозможным. Например:

  • Сайты, «вырывающиеся» из фреймов. Многие основные веб-свойства определяют, что они размещены в iframe, и просто не загружаются. x-ms-webview ведет себя как браузер при взаимодействии с содержимым.
  • События загрузки документов. В случае с iframe обнаружение окончания загрузки содержимого напоминает либо тактическую игру, либо отдельный вид искусства. Пытаясь использовать postMessage() для определения того, загружено ли содержимое DOM, x-ms-webview предоставляет широкий набор событий, что является неотъемлемой частью разработки приложений.

x-ms-webview устраняет все эти проблемы и предоставляет новые функции, недоступные в iframe:

  • Улучшенный доступ к локальному содержимому. Доступ к содержимому папки localstate для загрузки в x-ms-webview. Благодаря этому приложения для чтения электронных книг могут загружать книги из локальной папки.
  • Снимки экрана веб-содержимого. Возможность сделать снимок содержимого облегчает обмен содержимым через контракт общих данных.

Итак, отвечая на исходный вопрос, зачем приложениям на HTML и JavaScript нужен webview... Все эти функции означают, что x-ms-webview — это просто лучший способ отображения веб-содержимого в ваших приложениях.

Как выглядит x-ms-webview?

Обратимся к основам: Webview — это HTML-элемент, являющийся частью DOM для приложений на JavaScript. Мы добавляем x-ms- к названию элемента x-ms-webview, обозначая тем самым, что это специальная функция HTML от поставщика (например, x-vendor-feature). Использование этого элемента должно показаться знакомым, потому что его синтаксис схож с iframe.

HTML-элемент

<x-ms-webview id="webview" src="http://www.bing.com"></x-ms-webview>

JavaScript

var webview = document.createElement("x-ms-webview");

Добавление базового элемента управления x-ms-webview на страницу default.html в приложении Windows Store, написанном на JavaScript, выглядит так:

HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebView</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
 1: 
 2: 
 3: <script src="//Microsoft.WinJS.2.0/js/ui.js">
 1: </script>
 2: 
 3: <!— app references -->
 4: 
 5: <link href="/css/default.css" rel="stylesheet" />
 6: 
 7: <script src="/js/default.js">
</script>
</head>
<body>
<x-ms-webview id="webview" src="http://www.bing.com" width="500px" height="500px"></x-ms-webview>
</body>
</html>

Если просто добавить элемент управления x-ms-webview, его размер по умолчанию составит 100 х 100 пикселей. Вы можете задать ширину и высоту так же, как в случае с iframe, либо использовать CSS-стили для iframe.

Навигация с x-ms-webview

Теперь, когда вы познакомились с элементом управления x-ms-webview и тем, как он загружает содержимое, вы понимаете процесс навигации и можете контролировать происходящее. Одна из часто встречающихся у разработчиков для Windows 8 проблем при внедрении веб-содержимого в приложения — определение момента полной загрузки DOM, чтобы начать управление DOM-объектами или выполнение JavaScript. x-ms-webview поддерживает события путей навигации, а также историю навигации, предоставляя контроль над веб-содержимым, загружаемым в приложение.

Свойства и методы истории навигации

API для работы с навигацией x-ms-webview

navigate() — при вызове этого API вы можете также подписаться на следующие события, которые инициируются во время запроса Navigation:

Название события DOM Описание
MSWebViewNavigationStarting Обозначает начало навигации WebView
MSWebViewContentLoading HTML-содержимое загружено и сейчас вставляется в элемент управления
MSWebViewDOMContentLoaded Обозначает, что главные элементы DOM закончили загрузку
MSWebViewNavigationCompleted Обозначает, что навигация завершена, и все медиаэлементы отображены
MSWebViewUnviewableContentIdentified WebView обнаружил, что содержимое не является HTML

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

Название события DOM Описание
MSWebViewFrameNavigationStarting Обозначает, что iframe внутри WebView начинает навигацию
MSWebViewFrameContentLoading HTML-содержимое загружено и вставляется в элемент управления iframe
MSWebViewFrameDOMContentLoaded Обозначает, что главные элементы DOM закончили загрузку в iframe
MSWebViewFrameNavigationCompleted Обозначает, что навигация завершена, и все медиаэлементы отображены в iframe

История навигации x-ms-webview. 

Обнаружить, совершил ли пользователь навигацию внутри x-ms-webview, очень просто с помощью данных свойств и методов.

Свойства:

  • canGoBack— возвращает true/false, если элемент управления может вернуться к предыдущим страницам.
  • canGoForward— возвращает true/false, если элемент управления может перейти вперед.

Методы:

  • goBack()— осуществляет навигацию элемента управления на предыдущую страницу.
  • goForward()— осуществляет навигацию элемента управления на следующую страницу.

История навигации JavaScript

HTML

<body>

<p>Content goes here</p>

<x-ms-webview id="webview" src="http://t.msn.com"></x-ms-webview>

<div id="webviewNavigationButtons"><button id="goBack" onclick="goBack()" disabled>Back</button><button id="goForward" onclick="goForward()" disabled>Forward</button></div>

</body>

CSS

#webview{

width:500px;

height:500px;

}

button{

margin-right:15px;

}

JavaScript

webview.addEventListener("MSWebViewContentLoading", webViewContentLoading);

function webViewContentLoading(e) {

document.getElementById("goBack").disabled = !webview.canGoBack;

document.getElementById("goForward").disabled = !webview.canGoForward;

}

function goBack() {

webview.goBack();

}

function goForward() {

webview.goForward();

}

Источники контента

Теперь, когда мы знаем, что WebView — это простой HTML-элемент, давайте рассмотрим типы содержимого, которые можно загружать в x-ms-webview, и различные методы, доступные для каждого из них.

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

Интернет-содержимое

Чаще всего элемент x-ms-webview используется для интеграции онлайн-содержимого из Интернета. Например, мы разработали для конференции Build 2013 демонстрационное приложение — локальный каталог продуктов, использующий x-ms-webview для обработки заказа пользователя на существующем веб-сайте. Чтобы получить более подробную информацию о приложении, посмотрите выступление Джона Хэйзена (John Hazen) на Build — WebView: Bringing the Web to Your App.

Один из способов загрузки веб-содержимого в x-ms-webview — задание атрибута src в HTML-элементе. Задание атрибута src автоматически вызывает метод navigate()и передает ему строку URI с атрибутами.

<x-ms-webview id="webview" src="http://www.bing.com"></x-ms-webview>

Еще один способ загрузки веб-содержимого — вызов navigate() напрямую. Элемент управления x-ms-webview переходит на веб-сайты и загружает их — даже те, которые обычно не загружаются в iframe.

Примечание. Если атрибут src HTML-элемента задан и при загрузке приложения совершается вызов метода navigate, происходит двойная навигация.

Навигация поддерживает различные протоколы для получения доступа как к веб-, так и локальному содержимому. Примеры JavaScript предоставлены для каждого протокола.

Данная таблица содержит различные URI-схемы, поддерживаемые x-ms-webview. Для получения более подробной информации об этих схемах URI посетите портал MSDN.

Схема URI Описание
http:// Произвольное веб-содержимое
https:// Веб-содержимое через Secure Sockets Layer
ms-appdata:/// Содержимое, помещенное в локальную папку приложения
ms-appx-web:/// Содержимое, которое разработчик включил в пакет приложения, но которое не нужно рассматривать как веб-содержимое. Этот HTML не имеет доступа к Windows RT API
ms-local-stream:// Содержимое, загруженное разработчиком в поток памяти

Навигация по веб-содержимому в JavaScript

// Навигация webview
webview.navigate(new Windows.Foundation.Uri("http://www.msn.com"));
// Навигация к SSL-содержимому
webview.navigate(new Windows.Foundation.Uri(https://www.facebook.com));

Элемент управления navigateWithHttpRequestMessage() позволяет добавлять информацию о HTTP-запросах до навигации. За счет этого сервер получает возможность выполнить действия с запросом, прежде чем вернуть содержимое.

JavaScript — пример с Get

// Создаем URI, описывающий сайт, на который нужно перейти

var siteUrl = new Windows.Foundation.Uri("http://www.msn.com");

// Задаем тип запроса

var httpRequestMessage = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.get, siteUrl);

// Добавляем заголовки для запроса к веб-серверу для проверки кэша 

httpRequestMessage.headers.append("Cache-Control", "no-cache");

httpRequestMessage.headers.append("Pragma", "no-cache");

// Навигация WebView с помощью информации из запроса

webview.navigateWithHttpRequestMessage(httpRequestMessage);

JavaScript — пример с Post

// Создаем URI, описывающий сайт, на который нужно перейти

var siteUrl = new Windows.Foundation.Uri("http://www.msn.com");

// Задаем тип запроса

var httpRequestMessage = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.post, siteUrl);

// Задаем данные post

httpRequestMessage.Content = new Windows.Web.Http.HttpStringContent("cookie=abcxyz123");

// Навигация WebView с помощью информации из запроса

webview.navigateWithHttpRequestMessage(httpRequestMessage); webview.navigateWithHttpRequestMessage(httpRequestMessage);

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

Кроме того, вы можете направить x-ms-webview на локально хранимое содержимое, которое было включено в ваш пакет или загружено в папку local state. Поддержка автономного режима в приложениях обеспечивает оптимальную работу приложения для любых способов взаимодействия пользователя. Наиболее общий сценарий — когда игра должна работать в режиме офлайн.

В других случаях приложению может понадобиться большая производительность при загрузке и отображении содержимого, которую можно достичь только с помощью локального содержимого. Пример подобного сценария — программа для чтения EPUB-файлов. EPUB 3 форматы поддерживают содержимое HTML 5, CSS и JavaScript, которое с легкостью отображается в элементе управления x-ms-webview. Давайте рассмотрим API, которые можно использовать для загрузки локального содержимого в x-ms-webview.

JavaScript — переход к локальному содержимому

//Переход к содержимому, включенному в пакет appx

webview.navigate("ms-appx-web:///localPage.html");

//Переход к содержимому, хранящемуся в каталоге local state

webview.navigate("ms-appdata:///local/MyAppsLocalFolder/local.html");

JavaScript — переход к локальному содержимому

Простой пример, показанный выше, работает, но вы можете воспользоваться следующим примером для создания простого HTML-файла в каталоге local state.

// Переменные для local storage

var applicationData = Windows.Storage.ApplicationData.current;

var localFolder = applicationData.localFolder;

// Пишем локальный HTML-файл

function writeLocalHTMLThenNavigate() {

localFolder.createFolderAsync("MyAppsLocalFolder", Windows.Storage.CreationCollisionOption.openIfExists).then(function (folder) {

localFolder.createFileAsync("MyAppsLocalFolder\\local.html",

Windows.Storage.CreationCollisionOption.replaceExisting).then(function (htmlFile) {

var html = "<!DOCTYPE html><html><head>";

html += "<title>Local HTML Content</title></head>";

html += "<body><h1>Local HTML Content</h1></body></html>";

Windows.Storage.FileIO.writeTextAsync(htmlFile, html).then(function (e) {

document.getElementById("webview").navigate("ms-appdata:///local/MyAppsLocalFolder/local.html");

});

}).done(function () {

console.log("Local.html file created successfully.");

});

})

}
writeLocalHTMLThenNavigate();

Метод navigateToLocalStreamUri() предоставляет возможность перехвата содержимого до его загрузки в элемент управления. Наиболее общий сценарий использования — декодирование локального содержимого перед отправкой вывода в x-ms-webview. IUriToStreamResolver должен быть написан на C#/VB или C++, так что разработчикам JavaScript нужно включить дополнительный тип проекта для использования этих функций. В SDK уже есть готовый пример.

Пример: вызов navigateToLocalStreamUri из JavaScript полагается на лежащий в основе код C#, чтобы выполнить возврат потока. Для ознакомления с полным текстом примера обратитесь к SDK.

JavaScript — переход к потоку

function navigateToStreamWithCSResolver() {

var contentUri = document.getElementById("webview").buildLocalStreamUri("NavigateToStream", "simple_example.html");

var uriResolver = new SDK.WebViewSampleCS.StreamUriResolver();

document.getElementById("webview").navigateToLocalStreamUri(contentUri, uriResolver);

}

navigateToString() — создание и отображение динамического HTML часто встречается в приложениях, которым нужно использовать макет HTML для небольшого фрагмента контента, чтобы быстро отобразить его поверх содержимого или расширить возможности встроенной рекламы.

JavaScript — переход к строковому HTML-содержимому

var strHTML = "<!DOCTYPE HTML>";

strHTML += "<HTML>";

strHTML += "<HEAD><TITLE>NavigateToString() Example</TITLE></HEAD>";

strHTML += "<BODY><H1>HTML markup from a string</H1></BODY>";

strHTML += "</HTML>";

webview.navigateToString(strHTML);

Коммуникации от приложения к WebView

Очень часто бывает так, что приложению нужно связаться с веб-содержимым внутри x-ms-webview, чтобы улучшить удобство использования. Вы можете наладить связь между приложением и веб-сайтом, интегрировав такие функции Windows, как панель приложений, чудо-кнопка «Поиск» или чудо-кнопка «Поделиться», для обмена сообщениями между ними.

Использование метода invokeScriptAsync схоже с вызовом postMessage() в элемент . Приложение всегда может вызвать метод invokeScriptAsync в элементе управления, чтобы выполнить скрипт внутри встроенного содержимого. Однако для встроенного содержимого есть определенные ограничения при отправке сообщений с помощью события MSWebViewScriptNotify в родительский контейнер приложения.Host app to webcontent communication graphic .Изображение с коммуникацией между приложением-хостом и веб-содержимымВ данной

Название события DOM Описание
MSWebViewScriptNotify Данное событие инициализируется, когда страница внутри webview вызывает метод window.external.notify

В таблице показано, как элемент управления webview передает сообщения в родительское приложение.

Схема URI MSWebViewScriptNotify
http:// Нет
https:// Да*
ms-appdata:/// Нет**
ms-appx-web:/// Да
ms-local-stream:// Да

*Только если ContentURI заданы в Package.appxmanifest

**Может использовать UriResolver для подключения ScriptNotify

 
webview.addEventListener("MSWebViewScriptNotify", scriptNotify);

function scriptNotify(e) {

// Проверка URI, посылающего оповещение

if (e.callingUri == "https://myUri.com") {

doSomething(e.value);

}

}

JavaScript

var operation = webview.invokeScriptAsync("startAnimation", "500");

operation.oncomplete = function (e) {

console.log(e.target.result); 

};

operation.start();

Взаимодействие с содержимым x-ms-webview

Изображение демонстрирует вызов метода capturePreviewToBlogAsync для вывода изображения

Теперь вы можете получить снимок содержимого внутри x-ms-webview, встроенного в API. не может отображать произвольный HTML в виде растрового изображения. Однако метод capturePreviewToBlobAsync() элемента x-ms-webview позволяет получить изображение. JavaScript

var operation = webview.capturePreviewToBlobAsync();

operation.oncomplete = function (e) {

var url = window.URL.createObjectURL(e.target.result);

document.getElementById("imagetag").src = url;

};

operation.start();

Изображение демонстрирует, как выделенный HTML (текст + изображение) выводится в главное приложение

Вы можете с легкостью обмениваться содержимым из элемента управления x-ms-webview с помощью контракта«Общий доступ Windows». Встроенный API может извлекать содержимое, выбранное пользователем. Это содержимое затем может быть возвращено в ваше приложение для передачи другим приложениям, поддерживающим контракт получателя данных.

JavaScript — получение выбранного пользователем содержимого

var operation = webview.captureSelectedContentToDataPackageAsync();

operation.oncomplete = function (e) {

// Проверка, допустимо ли выделение

if (e.target.result) {

var data = e.target.result.getView();

if (data.contains(Windows.ApplicationModel.DataTransfer.StandardDataFormats.html){

// Данные содержат HTML, так что берем его!

data.getHtmlFormatAsync().then(function (htmlFormat) {

var htmlFragment = Windows.ApplicationModel.DataTransfer.HtmlFormatHelper.getStaticFragment(htmlFormat);

document.getElementById("output").innerHTML = htmlFragment;

});

}

}

};

operation.start();

Хотите узнать больше?

Как вы видите, элемент x-ms-webview — это мощный инструмент для отображения веб-содержимого в приложениях на HTML и JS. Если у вас уже есть приложение для Windows 8, использующее iframe для встраивания веб-содержимого, я очень советую обновить его и перейти на x-ms-webview в Windows 8.1. А если вы только начинаете создавать приложение, обязательно воспользуйтесь элементом x-ms-webview с самого начала.

Если вы хотите узнать больше об элементе x-ms-webview, посетите следующие замечательные ресурсы:

Кевин Хилл (Kevin Hill), старший руководитель программ, Windows