DevExpress, создав небольшую команду, и через несколько месяцев получила PhoneJS. Это стало решением для создания приложение под разные мобильные ОС при помощи HTML5.
Этот фреймворк не был написан с нуля, а был использован jQuery в связке с
библиотекой Knockout(без него не был бы реализован паттерн Model-View-ViewModel (MVVM) для javascript). Но как же PhoneJS получает доступ к файловой системе, камере, акселерометру и прочим функциям телефона? Все это реализовано при помощи
Apache Cordova (aka
PhoneGap ).
Layout-движок и UI-компоненты самых популярных мобильных ОС были построены на этом фундаменте.
Рассмотрим структуру приложения на примере простой демки TipCalculator:Вы находитесь в кафе/ресторане и Вам приносят счет, но вы не знаете сколько чаевых оставить. Это приложение поможет Вам рассчитать количество чаевых.
Посмотреть действие можно в
онлайн-симуляторе, а исходный код -
доступен на GitHub.
Точка входа — файл 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, однако есть и более функциональные варианты с навигационной панелью и так популярной сегодня боковой навигацией.
Есть и маршрутизация (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 очень проста.
ViewПерейдем к 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 создать мобильное приложение, обладая навыками веб программирования.
Запуск, отладка и упаковка для маркетовЧтобы произвести отлажку достаточно настроить ваш локальный веб-сервер на папку с исходными кодами и открыть URL на устройстве, в эмуляторе устройства или в браузере.
В браузере будет необходимо подменить строку UserAgent, чтобы он представлялся смартфоном или планшетом. К счастью, developer tools современных браузеров это легко позволяют.Есть путь, лишающий Вас от установки платформенных SDK — использовать онлайн-сервис
PhoneGap Build который позволяет бесплатно собирать одно приложение. С помощью PhoneGap Build, буквально через пару кликов можем получить мобильное приложение для разных платформ.
PhoneGap Build не поддерживает упаковку для Windows Phone 8 (планируют добавить позже в этом году), и для сборки пакетов понадобится Windows Phone SDK и шаблон CordovaWP8App, включенный в дистрибутив PhoneGap.Конечно же, придется зарегистрироваться как разработчик на сайтах Apple,
Google и Microsoft, но этот процесс хорошо описан для каждого из магазинов.
Для пользователей Visual Stuido у нас есть отдельный продукт
DXTREME Mobile (включающий PhoneJS в качестве одного из компонентов), позволяющий собирать приложения для iOS,
Android и Windows Phone 8 непосредственно из среды разработки.
Итак PhoneGap + PhoneJS — все что нужно для разработки мобильных приложений.