Мы видим этот тренд и видим примеры реализации пользовательских интерфейсов на HTML5, не уступающих по качеству нативным приложениям, и верим, что за HTML5 стоит будущее кросс-платформенных мобильных приложений.
В настоящее время веб-технологии и JavaScript, в частности — это очень либеральная среда, не привязанная к конкретным средствам и методологиям разработки. Как в любой подобной ситуации, с одной стороны это дает свободу, с другой стороны вносит долю хаоса.
Мы в DevExpress организовали небольшую команду, которая на протяжении нескольких месяцев анализировала и пробовала различные существующие средства и подходы. Результат полученного опыта — PhoneJS — наше комплексное решение для создания кросс-платформенных мобильных приложений на HTML5.
Мы не стали писать PhoneJS с нуля. Взяли jQuery, потому что сегодня для многих это синоним слова JavaScript. Затем добавили упоминавшуюся несколько раз на Хабре библиотеку Knockout, реализующую паттерн Model-View-View-Model (MVVM) для JavaScript, и выбрали MVVM рекомендованным подходом к структурированию приложения. Использование Apache Cordova (aka PhoneGap) позволило выйти из изоляции внутри WebView браузера и получить доступ к камере, файловой системе, акселерометру и другим функциям устройства. Сочетание этих компонентов помогло создать отличный фундамент для фреймворка.
На этом фундаменте мы построили layout-движок и UI-компоненты, адаптирующие свой внешний вид под три самых популярных платформы — iOS, Android и Windows Phone 8.
Стоит упомянуть, что всё большее количество сотрудников компаний пользуются на рабочем месте своими собственными мобильными устройствами. Идея создания кросс-платформенных приложений хорошо согласуется с этим трендом (известным под названием Bring Your Own Device, BYOD) и позволит сотрудникам устанавливать необходимое для работы корпоративное ПО на свои смартфоны и планшеты.
Сейчас на примере очень простой демки TipCalculator давайте посмотрим, как выглядит приложение на фреймворке PhoneJS. Несмотря на то, что TipCalculator состоит из одного экрана, его будет достаточно для понимания подхода и базовых принципов работы.
Приложение реализует алгоритм расчета чаевых. Исходный код доступен на GitHub, а посмотреть его в действии можно в онлайн-симуляторе.
В сущности, это Single Page Application на HTML5. Точка входа — файл index.html, в котором вы увидите только необходимые META-теги и подключение всех остальных ресурсов. Обратите внимание, как подключаются view-файлы
<link rel="dx-template" type="text/html" href="views/home.html" />
Такой подход позволяет избежать распространенной проблемы Single Page приложений, когда всю HTML разметку приходится держать в одном длинном index.html. Мы соблюдаем принципы декомпозиции приложения и облегчаем последующие этапы разработки и отладки.
В файле index.js объявляется пространство имен TipCalculator и создается объект-приложение:
TipCalculator.app = new DevExpress.framework.html.HtmlApplication(...)
Приложению мы сообщаем тип layout-а, используемый по умолчанию. В данном случае это самый простой из возможных — empty layout, однако есть и более функциональные варианты с навигационной панелью и так популярной сегодня боковой навигацией.
Здесь необходимо сделать отступление о том, что же такое layout вообще. В PhoneJS мы применили знакомую, проверенную и, давно известную вам идею декорации страниц (представлений, экранов) с помощью layout. Так делается в многочисленных серверных web-фреймворках (Ruby on Rails, ASP.NET MVC и многих PHP-библиотеках).
Подробнее про Views и Layouts можно почитать в нашей документации.
Есть и маршрутизация (routing):
TipCalculator.app.router.register(":view", { view: "home" });
Таким образом мы зарегистрировали простой маршрут, который из адресной строки (а если точнее, то из hash-сегмента) получает имя текущего экрана (view), причем экран «home» будет использоваться по умолчанию. Его и рассмотрим.
View Model
В файле views/home.js в пространство имен TipCalculator добавляется функция home, которая создает view-model (модель представления) для экрана home
TipCalculator.home = function(params) { . . . };
Есть три входных параметра: сумма чека (billTotal
), количество участников (splitNum
) и размер вознаграждения (tipPercent
). Они объявлены как observable, чтобы их можно было привязывать к UI-компонентам и отслеживать изменения значений
var billTotal = ko.observable(), tipPercent = ko.observable(DEFAULT_TIP_PERCENT), splitNum = ko.observable(1);
На основании пользовательского ввода вычисляются 4 результата: totalToPay
, totalPerPerson
, totalTip
и tipPerPerson
. Все четыре являются dependent observable (или computed) — то есть обновляются автоматически при изменении хотя бы одного observable, задействованного в вычислении результата.
var totalTip = ko.computed(...); var tipPerPerson = ko.computed(...); var totalPerPerson = ko.computed(...); var totalToPay = ko.computed(...);
Финальную сумму, как правило, округляют, для чего есть две функции roundUp
и roundDown
, изменяющие значение roundMode
. Его изменение влечет пересчет зависящего от него totalToPay
:
var totalToPay = ko.computed(function() { var value = totalTip() + billTotalAsNumber(); switch(roundMode()) { case ROUND_DOWN: if(Math.floor(value) >= billTotalAsNumber()) return Math.floor(value); return value; case ROUND_UP: return Math.ceil(value); default: return value; } });
Однако при изменении каждого из входных параметров необходимо сбросить округление, чтобы пользователь видел точные цифры, для этого с помощью метода subscribe
мы подписываемся на их изменение:
billTotal.subscribe(function() { roundMode(ROUND_NONE); }); tipPercent.subscribe(function() { roundMode(ROUND_NONE); }); splitNum.subscribe(function() { roundMode(ROUND_NONE); });
View model очень проста, особенно для тех читателей, кто уже знаком с Knockout. А для тех, кто не знаком, это хорошая демонстрация его возможностей.
View
Перейдем к HTML-разметке, а именно к файлу views/home.html. На верхнем уровне расположены два специальных div-элемента: для view с именем “home” задается разметка для области с именем “content”.
<div data-options="dxView : { name: 'home' }"> <div data-options="dxContent : { targetPlaceholder: 'content' }"> . . . </div> </div>
Внутри расположен тулбар:
<div data-bind="dxToolbar: { items: [ { align: 'center', text: 'Tip Calculator' } ] }"></div>
dxToolbar
— это виджет из состава PhoneJS. Его описание в разметке реализовано в виде Knockout-привязки (binding).
Ниже идут филдсеты. Для их создания применяются предопределенные во фреймворке CSS классы dx-fieldset
и dx-field
. Внутри поле для ввода суммы и два слайдера для процентов и количества человек:
<div data-bind="dxNumberBox: { value: billTotal, placeholder: 'Type here...', valueUpdateEvent: 'keyup', min: 0 }"> </div> <div data-bind="dxSlider: { min: 0, max: 25, step: 1, activeStateEnabled: true, value: tipPercent }"></div> <div data-bind="dxSlider: { min: 1, step: 1, max: 10, activeStateEnabled: true, value: splitNum }"></div>
Далее — две кнопки (dxButton
) для округления итоговой суммы и вывод результатов.
<div class="round-buttons"> <div data-bind="dxButton: { text: 'Round Down', clickAction: roundDown }"></div> <div data-bind="dxButton: { text: 'Round Up', clickAction: roundUp }"></div> </div> <div id="results" class="dx-fieldset"> <div class="dx-field"> <span class="dx-field-label">Total to pay</span> <span class="dx-field-value" style="font-weight: bold" data-bind="text: Globalize.format(totalToPay(), 'c')"></span> </div> <div class="dx-field"> <span class="dx-field-label">Total per person</span> <span class="dx-field-value" data-bind="text: Globalize.format(totalPerPerson(), 'c')"></span> </div> <div class="dx-field"> <span class="dx-field-label">Total tip</span> <span class="dx-field-value" data-bind="text: Globalize.format(totalTip(), 'c')"></span> </div> <div class="dx-field"> <span class="dx-field-label">Tip per person</span> <span class="dx-field-value" data-bind="text: Globalize.format(tipPerPerson(), 'c')"></span> </div> </div>
Даже на таком простом примере мы чётко видим, как быстро с помощью PhoneJS создать мобильное приложение, обладая навыками веб программирования. Минимум кода, структурированность и простота освоения.
Запуск, отладка и упаковка для маркетов
Приложения на HTML5 очень легко отлаживать. Достаточно настроить ваш локальный веб-сервер (Apache, IIS, nginx или любой другой) на папку с исходными кодами и открыть URL на устройстве, в эмуляторе устройства или в браузере. Правда в браузере будет необходимо подменить строку UserAgent, чтобы он представлялся смартфоном или планшетом. К счастью, developer tools современных браузеров это легко позволяют.
Другой удобный вариант — это Ripple Emulator, работающий в браузере.
Но нам хочется получить настоящее мобильное приложение, с возможностью публикации в маркеты (AppStore, Google Play и Windows Store).
Конечно же, придется зарегистрироваться как разработчик на сайтах Apple, Google и Microsoft, но этот процесс хорошо описан для каждого из магазинов, так что отдельно заострять внимание на этом не будем.
PhoneGap содержит нужные инструменты и шаблоны проектов. Основной сценарий работы с PhoneGap привязан к SDK мобильной платформы. Например, чтобы собрать APK для Android нужно будет установить Android SDK и создать в Eclipse PhoneGap-проект, а для разработки под iOS понадобится Mac.
Более простой путь, избавляющий нас от установки платформенных SDK — использовать онлайн-сервис PhoneGap Build, который позволяет бесплатно собирать одно приложение (для большего количества необходимо приобрести платный аккаунт). Имея необходимые сертификаты, с помощью PhoneGap Build, буквально через пару кликов можем получить мобильное приложение для разных платформ. Останется только подготовить описания, промо-материалы, картинки, иконки и приступать к публикации вашего приложения.
Небольшая ложка дегтя: на сегодняшний день PhoneGap Build не поддерживает упаковку для Windows Phone 8 (планируют добавить позже в этом году), и для сборки пакетов понадобится Windows Phone SDK и шаблон CordovaWP8App, включенный в дистрибутив PhoneGap.
Для пользователей Visual Stuido у нас есть отдельный продукт DXTREME Mobile (включающий PhoneJS в качестве одного из компонентов), позволяющий собирать приложения для iOS, Android и Windows Phone 8 непосредственно из среды разработки.
Итак PhoneGap + PhoneJS — все что нужно для разработки мобильных приложений
PhoneGap реализует доступ к аппаратным возможностям и решает задачу упаковки в нативные пакеты.
PhoneJS предоставляет инфраструктуру для Single Page приложений и набор оптимизированных под touch-устройства элементов для построения кроссплатформенного UI.
Списки с эластичной прокруткой, «бесконечной подгрузкой» и поддержкой жеста «pull down to refresh», переключатели ON/OFF, различные кнопки и поля ввода, галерея, карты и навигационные элементы — всё это есть в PhoneJS. Посмотреть примеры можно в демо-приложении Kitchen Sink.
Все виджеты можно использовать в двух режимах — как Knockout binding:
<div data-bind="dxCheckbox: {checked: checked} "></div> <script> var myViewModel= { checked: true }; ko.applyBindings(myViewModel); </script>
и как jQuery-плагин:
<div id="checkboxContainer" ></div> <script> $(function() { $("#checkboxContainer").dxCheckbox({ checked: true }); }); </script>
Предвосхищая естественный вопрос читателя, чем PhoneJS лучше / хуже / выделяется на фоне существующих известных решений, мы подготовили нашу реализацию для PropertyCross. Это интересный проект, цель которого сравнить разные существующие подходы к мобильной разработке.
Отметим важную деталь: PhoneJS не похож на большинство наших продуктов — он не привязан к определенному средству разработки. Дистрибутив — это zip-архив, а в качестве инструментов разработки и отладки можно использовать ваш любимый текстовый редактор, ваш любимый веб-сервер и developer tools вашего любимого браузера. Скачать PhoneJS можно по этой ссылке.
P.S. PhoneJS бесплатен для некоммерческого использования. А наша служба поддержки готова ответить на ваши вопросы и помочь преодолеть возникшие трудности.
ссылка на оригинал статьи http://habrahabr.ru/company/devexpress/blog/182134/
Добавить комментарий