Май 2016

Том 31 номер 5

Универсальные Windows-приложения - Размещенные веб-приложения для предприятия

Tim Kulp | Май 2016

Продукты и технологии:

Приложения Universal Windows Platform (UWP), JavaScript, веб-разработка, UWP Bridges

В статье рассматриваются:

  • применение UWP Bridges для передачи веб-приложений в Windows Store;
  • создание размещенных веб-приложений (hosted Web applications) в Visual Studio 2015;
  • расширение размещенных веб-приложений «родной» функциональностью;
  • работа с другими мобильными платформами в одном и том же размещенном веб-приложении.

Разработчики, работающие на предприятии с разветвленной структурой, знают, что внедрить новые технологии не всегда легко. Реализовать на предприятии нечто новое вроде проекта приложения Universal Windows Platform (UWP) может оказаться трудной задачей, когда у вас нет групп, уверенных в своих возможностях создать этот тип приложения. Многие предприятия вложили значительные инвестиции в свои веб-приложения интрасети и группы, которые их поддерживают. Размещенные веб-приложения (hosted Web applications, HWA) создают мост для корпоративных веб-приложений интрасети, через который их можно включить в Windows Store for Business с минимальными усилиями.

В этой статье я преобразую существующее веб-приложение интрасети в UWP-приложение для Windows Store, а затем расширю его «родной» для Windows функциональностью. Как показано на рис. 1, это веб-приложение Gotcha для поиска по социальным сетям (social recognition app), позволяющее сотрудникам Contoso Corp. находить своих коллег и выражать им признательность за добрые дела. Gotcha предназначено для дружеской оценки любых сотрудников и сплочения команды. Это веб-приложение является отличным кандидатом для Windows Store в том смысле, что оно обеспечивает простоту интеграции с контактами, средствами обмена информацией и камерой.

Веб-приложение Gotcha
Рис. 1. Веб-приложение Gotcha

Bridges и размещенные веб-приложения для предприятия

Для корпоративных разработчиков UWP Bridges и HWA имеют смысл, так как это позволяет им сохранить свои существующие наборы инструментов, процессы и системы развертывания приложений. Идея, лежащая в основе Bridges, — дать возможность разработчикам перенести существующие приложения для iOS, Android, Win32 или веб-приложения на UWP и в кросс-платформенный Windows Store. Благодаря этому разработчики смогут перенести свою существующую кодовую базу на UWP и оживить пользовательскую среду (UX) средствами, специфичными для Windows.

Bridges упрощают перенос кода на UWP, но корпоративные разработчики сталкиваются с другими трудными задачами, которые могут осложнить преобразование их кода. Разработчики в корпорации могут быть ограничены в выборе редакторов исходного кода или места развертывания кода в зависимости от степени конфиденциальности информации внутри приложения. Истинная ценность UWP Bridges для предприятия заключается не в простоте преобразования приложений, а в возможности сохранить существующие корпоративные инструменты разработки ПО, практики и систему управления изменениями при доставке UWP-приложений через Windows Store.

В качестве примера HWA (также известные под названием «Project Westminster») позволяют разработчикам встраивать веб-приложения в какое-либо UWP-приложение. Создав UWP-приложение с расчетом на использование контента HWA, разработчики могут применять существующие у них практики для сопровождения веб-приложения, которое будет автоматически обновлять соответствующую часть UWP-приложения. С помощью HWA Bridge разработчики могут сосредоточиться на своем веб-приложении и включать средства, специфичные для UWP, через распознавание таких средств (feature detection). Работа с имеющейся интрасетью — отличный вариант использования для UWP Bridges, но разработчики вне предприятия также могут задействовать HWA, чтобы сделать доступными собственные веб-приложения в Windows Store. Любой веб-сайт может быть HWA, если он проходит процесс сертификации в Windows Store.

Основы HWA исчерпывающе рассмотрены в статье Кирилла Сексенова «Project Westminster in a Nutshell» (bit.ly/1PTxxW4). Советую прочитать эту статью, чтобы получить более глубокое понимание идей, лежащих в основе HWA.

Приступаем к проекту Web HWA

Чтобы приступить к конвертации веб-приложения Gotcha в HWA, я создаю новый проект JavaScript UWP App в Visual Studio. Создав приложение, открываю манифест пакета и указываю URL веб-приложения в качестве начальной страницы UWP-приложения, как показано на рис. 2. В данном случае веб-приложение Gotcha запускается с localhost:6107. После этого приложение будет отображать веб-страницу по указанному адресу вместо своего локального контента.

Настройка начальной страницы в манифесте пакета
Рис. 2. Настройка начальной страницы в манифесте пакета

Наконец, задайте в манифесте пакета URI-идентификаторы контента. Эти URI будут сообщать вашему приложению, какие страницы могут обращаться к библиотекам Windows Runtime (WinRT) и какой уровень доступа могут иметь эти URI. Я слышал, что этот процесс описывают как определение того, где заканчивается приложение и начинается Интернет, и, как мне кажется, это хороший умозрительный образ того, как используются URI контента. В существующем веб-приложении Gotcha есть четкое разделение между тем, что делает приложение и как оно может использовать для этого Интернет. Например, в Gotcha пользователи могут делиться своими оценками в социальных сетях вроде LinkedIn. Веб-сайт LinkedIn не является частью UWP-приложения Gotcha; это часть Интернета. Я включу только те URI, которые напрямую применяются в приложении, и лишь те из них, которым нужен доступ к UWP API.

Применение URI контента позволяет разработчику защищать пользователей приложения, предотвращая доступ к библиотекам WinRT по незарегистрированным URI. Для каждого URI указывайте необходимый уровень доступа к библиотекам WinRT.

  • All JavaScript-код, выполняемый в веб-приложении (в данном случае — в Gotcha), может обращаться к любым UWP API, определенным через App Capabilities.
  • Allow for Web Only JavaScript-код, выполняемый в веб-приложении, может запускать пользовательские WinRT-компоненты, включенные в пакет приложения, но не может обращаться ко всем UWP API.
  • None JavaScript-код, выполняемый в веб-приложении, не может обращаться к локальным UWP API (настройка по умолчанию).

При задании URI контента помните, что это ключевой компонент защиты для пользователя UWP-приложения. Убедитесь, что вы выдаете URI лишь минимальные разрешения для необходимых функций UWP-приложения, как показано на рис. 3. Старайтесь избегать установки корневого URI WinRT Access в All, если только это действительно нужно в приложении.

Выдача URI контента наименьшей привилегии, необходимой для работы приложения
Рис. 3. Выдача URI контента наименьшей привилегии, необходимой для работы приложения

Не рекомендую удалять существующий контент, который предоставляется вам в процессе создания проекта (например, папки .css, .js и WinJS). Этот контент дает разработчикам великолепную инфраструктуру, применимую для добавления локального контента в Web HWA. Далее в этой статье я задействую эти папки для локального контента, чтобы создать некоторые средства, дополняющие автономные (в отключенном от сети состоянии) возможности Web HWA.

Сконфигурировав манифест пакета, запустите UWP-приложение. Как видно на рис. 4, теперь веб-приложение будет появляться в окне приложения, как и любое другое UWP-приложение.

Приложение Gotcha, готовое для Windows Store
Рис. 4. Приложение Gotcha, готовое для Windows Store

Отладка размещенного веб-приложения

Отладка HWA несколько отличается от таковой для чисто «родных» приложений. Откройте UWP-приложение и нажмите F12. На экране появятся F12 Developer Tools для UWP-приложения. С помощью F12 Developer Tools я могу отлаживать, профилировать и тестировать веб-приложение точно так же, как в браузере. Хотя разработчикам HWA пригодятся все средства F12 Developer Tools, наиболее полезными компонентами я считаю поддержку отладки вне Visual Studio и профилирования сетевой активности. Я использую эти средства, чтобы разобраться в специфических поведениях приложения и понять источники любых проблем (вроде кеширования).

Как и при использовании F12 в браузере, разработчики могут изменять DOM и экспериментировать с разными UI в зависимости от размера экрана или окна. Это пригодится при исследовании изменений в разметке веб-приложения для адаптации к требованиям приложения. В качестве примера фиксация UWP-приложения для отображения как боковой панели должна приводить к пересчету размеров и позиций UI-элементов. Если изменение размера не вызывает такого пересчета в приложении, F12 Developer Tools помогут определить причину и поэкспериментировать с DOM, чтобы понять, что нужно для достижения правильного пересчета.

Добавление функциональности для UWP-приложения

Подготовив базовое HWA, я намерен заняться возможностями веб-приложения, чтобы включить некоторые UWP API и оживить пользовательскую среду (UX). Веб-приложения интрасети могут иметь ограничения, которых нет у HWA. Используя UWP API, HWA может обращаться ко многим локальным средствам UWP-устройства (например, к камере, определению местонахождения и различным датчикам). Для начала подумаем о случаях применения, которые стимулируют реализацию веб-приложения в виде размещенного веб-приложения. В Gotcha я хочу, чтобы у пользователей была возможность выбирать из своих контактов, кому присудить награду, а не просто набирать имя этой персоны и прикреплять какой-то снимок для узнавания.

Первым делом я создаю в веб-приложении удаленный файл GotchaNative.js (файл скриптов GotchaNative.js будет размещен на удаленном сервере веб-приложения), который будет распознавать пространства имен «родных» API и выполнять соответствующий код, чтобы инициировать наши случаи применения с использованием «родной» функциональности. Добавьте в файл NativeGotcha.js следующий код:

var GotchaNative = (function () {
  if (typeof Windows != 'undefined') {
    // Здесь добавляем нахождение контакта...
    // Здесь добавляем снимок, сделанный камерой...
  }});

Этот код создает объект GotchaNative, который будет хранить всю функциональность UWP API. Централизация этих API позволяет включать один файл в страницы, где требуется функциональность UWP API. Я изолирую этот файл, чтобы иметь возможность явным образом объявить URI контента, включающие этот специфический файл, как URI с доступом к необходимым UWP API. Тем самым я могу реализовать концепцию защиты «принцип наименьшей привилегии» и выдавать разрешения только URI, которым необходим доступ к UWP API.

Другое преимущество изоляции этого файла — подготовка и для других платформ. Об этом мы поговорим далее в этой статье, а пока рассматривайте этот файл как место хранения всей «родной» функциональности, которая будет включена в веб-приложение Gotcha.

Расширение существующей функциональности

Создав объект GotchaNative, можно добавить специфическую функциональность для подключения HWA к UWP API. В первом случае применения веб-приложение Gotcha дает возможность пользователям вводить персону для одобрения. В UWP у пользователей есть приложение People, которое хранит контакты и было бы гораздо проще для пользователей в выборе нужного человека, чем ввод его имени. Замените комментарий «Здесь добавляем нахождение контакта...» в файле GotchaNative.js на:

this.FindContact = function () {
  var picker = new Windows.ApplicationModel.
    Contacts.ContactPicker();
  picker.desiredFieldsWithContactFieldType.append(
    Windows.ApplicationModel.Contacts.ContactFieldType.email);
  return picker.pickContactAsync();
}

Это базовый код для подключения к ContactPicker API, позволяющему выбирать контакт из списка контактов. Список UWP API, которые можно включать в Web HWA, находится на сайте rjs.azureWebsites.net. На этом веб-сайте перечислены некоторые из более популярных API с кодом, готовым для копирования и вставки, чтобы помочь вам в разработке проекта Web HWA.

Функциональность для добавления персоны можно найти в Person View Model для веб-сайта Gotcha. Добавьте в Person View Model код с рис. 5.

Рис. 5. Код для добавления в Person View Model

if (Windows != undefined) {
  var nativeGotcha = new NativeGotcha();
  nativeGotcha.FindContact().done(function (contact) {
    if (contact !== null) {
      $("#txtWho").val(contact.displayName);
    } else {
      // Никакие контакты не выбраны
    }
  });
}
else {
  $('#add-person').on('shown.bs.modal', function () {
    $("#txtWho").focus();

}

В коде на рис. 5 используется метод FindContact, если объект Windows определен благодаря скрипту, выполняемому как HWA. Если же объект Windows не определен, веб-приложение продолжит использовать существующее модальное окно Bootstrap для сбора информации о персоне для одобрения. Этот код позволяет веб-приложению применять один подход для ввода нужной персоны, а UWP-приложение может использовать другой подход, более адаптированный под «родную» среду.

Добавление новой функциональности

Иногда включение UWP API позволяет включать новую функциональность, которая обычно отсутствует в веб-приложении. В Gotcha HWA я хочу разрешить пользователям делать снимки и отправлять их для одобрения другим пользователям Gotcha. Эта функциональность будет новой для этого приложения, которой нет в веб-приложении. При создании HWA подумайте над возможностями, открываемыми UWP API для приложения.

В Gotcha HWA я хочу разрешить пользователям делать снимки и отправлять их для одобрения другим пользователям Gotcha.

Чтобы приступить к реализации этой новой функциональности, сначала замените комментарий «Здесь добавляем снимок, сделанный камерой...» в файле GotchaNative.js следующим кодом:

this.CapturePicture = function () {
  var captureUI = new Windows.Media.Capture.CameraCaptureUI();
  captureUI.photoSettings.format =
    Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
  return captureUI.captureFileAsync(
    Windows.Media.Capture.CameraCaptureUIMode.photo);
}

В этом коде я открываю UI захвата снимка, позволяю сделать снимок, а затем возвращаю снимок вызвавшему коду. Эта новая функция должна быть разрешена в веб-приложении, если определен объект Windows. Используя распознавание функционала, как это делалось в Person View Model, я добавляю код с рис. 6 в Home View Model.

Рис. 6. Код распознавания функционала, добавляемый в Home View Model

$('#give-modal').on('shown.bs.modal', function () {
  if (typeof Windows != 'undefined') {
    var gotchaNative = new NativeGotcha();
    $("#btnCamera").click(function () {
      gotchaNative.CapturePicture().then(
        function (capturedItem) {
        // Что-то делаем с capturedItem;
      });
    }).show();
  }
  else {
    $("#btnCamera").hide();
  }
})

В коде на рис. 6 я скрываю btnCamera, если объект Windows не определен. А если он определен, тогда я настраиваю событие щелчка на запуск функции CapturePicture. Для краткости я оставил комментарий вместо операции над снимком. При включенной камере я должен учитывать, что это HWA все же является UWP-приложением, которому нужно разрешить использование функции Webcam, что делается через манифест пакета.

Корпоративные веб-приложения можно конвертировать в HWA и использовать UWP API магазина Windows Store. На основе существующих веб-приложений легко создавать UWP-приложения в Windows Store, но HWA предполагают наличие соединения с Интернетом. Далее я покажу, как обеспечить работу приложения даже в отсутствие доступа к Интернету.

Подключение в автономном режиме

UWP-приложение может иметь локальные файлы, которые позволяют работать в автономном, или локальном, режиме. Используя локальный контент, вы можете отключать некоторые из UWP API, вызываемых из размещенного веб-приложения. Как и для функции распознавания, которая уже создана, связывание с локальным контентом можно осуществлять через активацию ссылок. В случае Gotcha я добавлю функцию работы с картами, использующую локальные элементы управления картами.

В HWA можно использовать ту же функцию распознавания, которая ранее применялась в Home View Model. Правильная схема URI позволит HWA переходить между веб-контентом и локальным контентом. На начальный экран я добавлю такую ссылку:

<a href="ms-appx:///default.html" id="lnkMap">
  <span class="glyphicon glyphicon-map-marker">
    &nbsp;</span> Show Map
</a>

Эта ссылка связывает со схемой ms-appx:///, которая позволяет приложению подключаться к локальному контенту внутри пакета приложения. При работе со схемой ms-appx приложение может подключаться к необходимым UWP API. Это аналогично использованию URI контента для объявления уровня доступа страницы к API. Применение ms-appx подобно пометке URI как All. В этом случае страница default.html имеет доступ к UWP API. Когда в HWA появляется ссылка, пользователи могут щелкнуть ее, чтобы работать с контентом внутри пакета приложения.

Для корпоративных разработчиков такая функциональность дает возможность изолировать случаи применения, специфичные для UWP, и обойтись без обязательного подключения к веб-приложению. Подключение к контенту пакета также позволяет избегать предоставления веб-приложению доступа к UWP API и ограничить весь доступ рамками пакета.

Можно ли использовать более одного магазина?

В ряде организаций может существовать среда Bring Your Own Device (принеси свое устройство). А значит, такая организация может уже предусматривать работу с устройствами iOS или Android в существующих приложениях. Приложения Android и iOS имеют концепции, сходные с HWA и реализованные в элементе управления WebView. WebView позволяет разработчикам предоставлять какое-либо окно в своих приложениях для существующего веб-приложения и последующего взаимодействия с этим веб-приложением так, будто оно является частью «родного» приложения (звучит знакомо?). HWA можно создавать так, чтобы они хорошо взаимодействовали с другими приложениями, адаптируя функциональность существующего веб-приложения под платформу, доставляющую это веб-приложение. Я обновлю GotchaNative.js для поддержки Android и покажу, как код HWA будет сосуществовать бок о бок с JavaScript, ориентированным на другие платформы.

Ранее я подготовил GotchaNative.js, что означает хранение всего «родного» кода в приложении. ViewModel будут обрабатывать вывод «родных» методов. Использование API любой платформы аналогично HWA: сначала приложение должно определить, доступны ли «родные» API, а затем вызывать соответствующий API. Приступая к обновлению GotchaNative.js, я добавлю свойство, которое будет сообщать мне, какая «родная» платформа (если таковая есть) обнаружена. В следующих примерах я предполагаю, что приложение Android использует WebView, который объявляет «Android» как пространство имен локального скрипта:

this.Platform = function () {
  if (Windows != 'undefined')
    return "Windows";
  else if (Android != 'undefined')
    return "Android";
  else
    return "Web";
}

Эта функция позволяет моему коду определить, с какой платформой придется работать, поэтому я могу подстроить код под эту платформу. Отсюда каждый метод в GotchaNative.js может проверять платформу, чтобы выяснить, как действовать дальше (рис. 7).

Рис. 7. Методы в GotchaNative.js, проверяющие платформу

this.CapturePicture = function () {
  switch (this.Platform()) {
    case "Windows":
      var captureUI =
        new Windows.Media.Capture.CameraCaptureUI();
      captureUI.photoSettings.format =
        Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
      return captureUI.captureFileAsync(
        Windows.Media.Capture.CameraCaptureUIMode.photo);
      break;
    case "Android":
      // Вызов Android-кода в «родном» приложении
      Android.CaptureFile();
      break;
    default:
      return null;
      break;
}

Теперь во всех ViewModel код будет обновлен на использование функции распознавания платформы, чтобы знать, что делать с выводом методов GotchaNative. Ниже я обновляю код для события кнопки камеры из HomeViewModel:

$("#btnCamera").click(function () {
  switch (gotchaNative.Platform()) {
    case "Windows":
      gotchaNative.CapturePicture().then(
        function (capturedItem) {
        // Что-то делаем с capturedItem;
      });
      break;
    case "Android":
      // Обрабатываем вывод для Android
      break;
  }
}).show();

Теперь, когда приложение поддерживает больше платформ, у меня есть единое место в коде для расширения возможностей под все платформы. Если завтра выйдет новая ОС, группа разработки сможет адаптировать код и под эту новую платформу.

Заключение

Корпоративные разработчики сталкиваются с множеством трудных задач в своей работе. Стандартизованные процессы и инструментарий могут оказаться барьером на пути к внедрению новых технологий вроде UWP-приложений. UWP Bridges позволяют корпоративным разработчикам размещать свои существующие внешние веб-приложения или веб-приложения для интрасетей в Windows Store (либо как общедоступные, либо как Windows Store for Business). Bridges для HWA могут превратить веб-приложение в кросс-платформенное UWP-приложение, используя UWP API для оживления пользовательской среды.

В этой статье я исследовал, как преобразовать существующее веб-приложение в HWA, в то же время добавляя специфичные для UWP-приложения средства вроде доступа к камере и контактам. На основе схемы ms-appx я показал, как переходить из размещенного веб-приложения к локальному контенту внутри пакета приложения. Наконец, я продемонстрировал, что при некоторой доле планирования HWA можно создавать с расчетом на множество разных платформ, позволяя предприятию не отставать от постоянно расширяющегося мира мобильных устройств. Благодаря этим подходам HWA могут задействовать существующие инвестиции в веб-приложения, помогая предприятиям присоединиться к экосистеме Windows Store.


Тим Кульп (Tim Kulp) — старший технический архитектор, живет в Балтиморе (штат Мериленд). Занимается разработкой для Web, мобильных устройств и UWP-приложений, а также является автором, художником и папой. Вы найдете его в Twitter (@seccode) или через LinkedIn (linkedin.com/in/timkulp).

Выражаю благодарность за рецензирование статьи экспертам Microsoft Джону-Дэвиду Дальтону (John-David Dalton) и Кириллу Сексенову (Kiril Seksenov).


Discuss this article in the MSDN Magazine forum