В этом году сайт Airport Parking Shop исполняется 11 лет.
На протяжении последних нескольких лет мы наблюдали как популярность мобильных устройств (в том числе и планшетов) повысилась с отметки
8% в 2011 году до 44% в 2014. Этот тренд невозможно было игнорировать и поэтому мы полностью перестроили наш сайт для удобства пользования им через различные мобильные устройства.
Не смотря на то, что сайт стал очень функциональным и оптимизированным под мобильные устройства, мы решили пойти еще дальше. Следующий наш логический шаг было предложить пользователям Android и iOS специальные приложения.
Мы уже имели опыт создания приложений PhoneGap, Java (Android) и Objective-C (iOS), поэтому без труда смогли взвесить все за и против, которые выглядят так:
За | Против | |
PhoneGap | Мультиплатформа. Знакомые разработчикам веб-технологии (CSS, HTML, JS) | Медленный и неотзывчивый по сравнению с родными приложениями. Много специфических нюансовСложно проектировать, выпускать и т.д. (из-за иконок, заставок, сертификатов и т.д.) |
Android Java Eclipse | Высокая скорость. Более натуральный вид по сравнению с стандартными UI компонентами в SDK | Одна платформа. Необходимы навыки работы с JavaИспользование Eclipse (хотя может некоторых это и не смутит)Все что связано с SDK (то, что он предлагает или не может предложить) |
iOS Objective-C Xcode | Высокая скорость. Прекрасный визуальный UI редактор и другие инструментыЛегко тестировать, проектировать и работать | Подходит только для MacОдна платформаТребуются навыки работы с Objective-C |
Почему Ionic
Взвесив все указанные факторы, мы решили приглядеться к Ionic.
Ionic является относительно новым фреймворком для создания гибридных мобильных приложений (веб-технологии представлены как родные приложения), то есть их repo отмечено 11000 раз, а фреймворк имеет более 13К подписчиков в Twitter.
По сути, Ionic – это обертка уже очень популярного фреймворка Apache Cordova (читай PhoneGap), но со своими очень сильными инструментами CLI и внушительной документацией. Впечатляюще для такого молодого проекта.
На официальном сайте Ionic дают определение как «Работа, которая завладеет вашим умом». Именно по этой причине мы решили отложить PhoneGap и гибридные приложения в долгий ящик, но вскоре мы решили испробовать их еще раз. Этот фреймворк сопровождают прекрасные компоненты UI, использует Bower & NPM и написан с помощью AngularJS и SASS, которые являются самыми популярными инструментами и фремворками и, одновременно, основными причинами популярности Ionic
Начинаем работу с Ionic
Прежде всего, Ionic – это программный пакет NPM, поэтому необходимо удостовериться в том, что у вас уже установлен Node и NPM, а затем начать:
1
|
npm install -g cordova ionic
|
Так вы установите настройки инструментов Ionic CLI, и вы сможете создать заготовку своего первого приложения с помощью одной единственной команды:
1
|
ionic start --sass -appname "Airport Parking Shop" --id com.fubra.aps aps_app tabs
|
Заготовка приложения готова и нам остается добавить ‘cd’ в каталог приложений и запустить работу.
1
|
ionic serve
|
Так заработает сервер Ionic и загрузит ваше новое приложение в браузер!
Структура файла заготовки должна быть знакома всем, кто имел дело с PhoneGap или AngularJS. Все файлы приложения, HTML, CSS & JS, находятся в каталоге www, а плагины Cordova plugins, SASS и т.д., в корневом каталоге приложения.
В www вы увидите типичное приложение AngularJS с контроллерами и темплейтами.
Несмотря на то, что знание AngularJS не обязательно, оно поможет вам намного быстрее освоить документацию Ionic.
Ionic предлагает прекрасный обучающий портал learn.ionicframework.com. Может еще пригодиться сайт StackOverflow.
Создание приложения Airport Parking Shop
Наше приложение использует простую целевую страницу с формой цитаты, которая составлена из избранного списка и некоторых сборщиков даты/времени.
Чтобы настроить основной вид мы выбрали простой маршрут www/js/app.js, указывающий на наш шаблон quote.html. в каталоге www/js/controllers/ в качестве контроллера мы выбрали QuoteCtrl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// Configure routing
.config(function($stateProvider, $urlRouterProvider) {
// Configure routes
$stateProvider
.state('main', {
url: '/',
templateUrl: 'templates/quote.html',
controller: 'QuoteCtrl'
});
// Default Route
$urlRouterProvider.otherwise('/');
})
|
Затем, мы написали разметку для нашей формы quote и посмотрели опции элементов выбора дата/время, а там есть из чего выбрать. Это не значит, что мы хотели выпустить нечто похожее на jQuery, мы хотели получить нечто оптимизированное для мобильных устройств, а что еще важнее, мы хотели, чтобы получился продукт, который будет готовиться быстро и с наименьшим количеством кода.
Таким образом, очевидным выбором стала оригинальная дата и время HTML5.
1
2
3
|
<input type="date"/>
<input type="time"/>
|
Они прекрасно работают и на iOS и на Android (4.4+).
Финальная форма quote выглядит так:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<!-- quote form -->
<div class="row responsive-sm">
<div class="col col-50 col-offset-25">
<div class="list box">
<label class="item item-input item-select item-divider">
<div class="input-label">
<strong>Airport</strong>
</div>
<select class="close-left" ng-model="pickers.airport">
<option value="ABZ">Aberdeen</option>
<option value="BHD">Belfast City (George Best)</option>
... and so on
</select>
</label>
</div>
<div class="list box">
<div class="item item-divider">Drop-Off</div>
<div class="item picker-input">
<input type="date" ng-model="pickers.startDate" ng-change="updateCleanEnd()" class="date close-right" />
<input type="time" ng-model="pickers.startTime" class="time" />
</div>
<div class="item item-divider">Collect</div>
<div class="item picker-input">
<input type="date" ng-model="pickers.endDate" ng-change="setDirty()" class="date close-right" />
<input type="time" step="60" ng-model="pickers.endTime" ng-change="setDirty()" class="time" />
</div>
</div>
</div>
</div>
|
Мы написали очень простой сервис, который называется Airport-Parking-Shop REST API. Мы уже используем его на нашем сайте.
Сервис использует объект AngularJS $http для запроса GET и снова использует построенный на объекте $q во фреймворке AngularJS. Основной метод сервиса такой:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
params.callback = 'JSON_CALLBACK';
// Create promise
var deffered = $q.defer();
// Do request
$http({
method: 'JSONP',
url: 'http://www.airport-parking-shop.co.uk/rest-api',
params: params,
cache: false
}).success(function(data) {
// Check results was found
if (data.status === 200 && data.results.length) {
// Resolve with success
deffered.resolve({
status: 200,
results: data.results
});
} else {
// Resolve with no content
deffered.resolve({
status: 204
});
}
// If error then simply resolve with error
}).error(function() {
// Resolve with error
deffered.resolve({
status: 500
});
});
|
Главной возможностью было то, что пользователь мог перейти на предыдущую страницу и сохранить точность введенного запроса. Конечно, этого можно было бы добиться различными способами, используя маршрутизатор AngularJS, cookie и так далее, но мы выбрали стандартный модальный отображаемый элемент Ionic, чтобы вводить минимальный код. Посмотрите, как это может выглядеть:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<ion-modal-view id="results" ng-controller="ResultsCtrl">
<!-- Header bar -->
<div class="bar bar-header bar-positive">
<!-- Back Button -->
<button ng-click="modal.hide()" class="button button-positive icon ion-chevron-left"></button>
<h4 class="title">{{airport}} Parking</h4>
</div>
<!-- Main content -->
<ion-content class="has-header has-subheader" ng-class="{ 'ios' : ios }">
<!-- Visible when all results is filtered -->
<div id="bgMsg">No Results</div>
<!-- Results List -->
<ion-list>
<ion-item ng-click="openBrowser('{{item.bookingUrl}}')" target="_blank" ng-repeat="item in results | orderBy:predicate" ng-show="carpark_type[item.parking_type]" class="result item-icon-right">
<div class="row">
<div class="col">
<h3>{{item.carpark_name}}</h3>
<p>
<img src="img/stars/stars_{{item.avg_rating}}.png" class="rating">
<i class="{{item.parking_type}} ion-record key"></i>
<small>via {{item.partner_name}}</small>
</p>
<p class="info">
<span class="ion-clock">{{item.transfer_time_int}}
<span ng-show="item.transfer_time_int != 'N/A'">mins</span>
</span>
<span class="ion-ios7-loop-strong" ng-show="item.transfer_time_int > 0">{{item.transfer_freq}}</span>
</p>
</div>
<div class="col col-20 price">
<div class="loading logo_container" rn-lazy-background="'{{item.logoImage}}'" rn-lazy-loading-class="loading" rn-lazy-loaded-class="loaded"></div>
<strong>{{item.amount | currency: "£"}}</strong>
</div>
</div>
</ion-item>
</ion-list>
</ion-content>
</ion-modal-view>
|
Модальный отображаемый элемент может быть инициирован и его можно контролировать фрагментом кода JS.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// Create results modal
$ionicModal.fromTemplateUrl('templates/results.html', {
scope: $scope,
animation: 'slide-in-right'
}).then(function(modal) {
$scope.modal = modal;
});
// Show Results
$scope.modal.show();
|
Наконец, имея рабочую форму quote, API сервис и просмотр результатов, нам нужно найти способ связаться с сайтами владельцев автопарка, где пользователи смогут сделать заказ или вернуться на предыдущую страницу для продолжения поиска, где результаты поиска останутся прежними, т.е. странице не будет перезагружаться.
Теперь, с нашими результатами JSON, мы создаем страницу, где будет показан список результатов.
Связь с браузером девайса была опцией, но это может отбросить пользователя на несколько шагов назад от приложения, что не привлекательно. К счастью, Ionic поддерживает все стандартные плагины Cordova/PhoneGap, таким образом, мы выбрали плагин браузера в приложении и благодаря инструментам Ionic CLI, установка плагина стала предельно простой.
1
|
ionic plugin add org.apache.cordova.inappbrowser
|
Веб-сайт автопарка в выскакивающем браузере может быть закончен с помощью отрывка JS, который выглядит примерно так:
1
2
|
// Create inappbrowser
var browser = window.open(url, '_blank', 'enableViewportScale=yes,closebuttoncaption=Back');
|
Теперь, когда приложение готово, пришло время его тестировать и отправлять в массы!
Тестируем наше приложение
Мы потратили чуть больше недели на написание кода и пытались пристроить UI в удобное место, и все это происходило на удивление легко, но настоящие проблемы начались, когда мы стали тестировать приложение вне браузера и подготавливать приложение к работе.
Ionic CLI упрощает тестирование на девайсах, нам нужны только две команды, так называемые ionic emulate и ionic run.
Но прежде чем использовать эти команды, вы должна добавить платформы, для которых вы готовите приложение. В нашем случае это iOS and Android:
1
2
|
ionic platform add ios
ionic platform add android
|
Это создает специфические надстройки в каталоге каждой платформы, где работа над приложением будет доведена до логического завершения.
Для завершения работы и запуска приложения на имитаторе устройства, таком как iPhone Simulator XCode или Android SDK Device Emulator, просто введите
1
|
ionic emulate ios
|
Как альтернатива, можно управлять приложением прямо на подключенном устройстве:
1
|
ionic run ios
|
Работа с iPhone Simulator проходит без загвоздок, чего нельзя сказать об Android.
Android Emulator не оправдывает наших ожиданий, поэтому мы используем альтернативу, предлагаемую Genymotion.
Приложение Genymotion быстро устанавливается, имеет большой набор бесплатных опций наряду с платными опциями, которые предназначены широкому кругу разработчиков. Несмотря на стоимость, это приложение очень помогло нам с тестированием нашего приложения для Android и становится необходимостью при работе с Ionic в создании приложений для Android.
Наверное, нужно отметить, что Genymotion эмулятор не использует приложение ionic emulate android, а скорее ionic заставляет работать android так, будто это реальное устройство.
Теперь, когда мы завершили тестирование на имитаторах и реальных устройствах, стало ясно, что хотя браузер и является хорошим помощников разработчика, он все же слишком далек от сегодняшних девайсов и выдает слишком много ошибок, которые приходится устранять.
Еще одной проблемой для нас стала установка иконок приложения и заставки. В первую очередь, это означает, что необходимо вносить изменения в каталоге «платформы», чего бы нам очень не хотелось делать. Во-вторых, то каким образом эти иконки и заставки были уставлены в Ionic никак не подходили под сертификацию Apple и Android.
Все закончилось тем, что мы воспользовались очень полезным сайтом makeappicon.com, который смог предложить нам список иконок очень похожих на тех, что имеет Ionic.
Несмотря на то, что все это не является сложной задачей, на это ушло 2 дня, и советуем вам обратить на это внимание. Все это означает, что Ionic все еще находится в разработке, а оказанный интерес и соответствующие вложения очень скоро поспособствуют упрощению процесса работы.
Распространение приложения
Спустя две недели работы с Ionic framework мы имели приложение, которое хорошо работало как на iOS так и на Android.
Ionic стал очень детальным гидом, который помогает строить и распространять приложения Android, но мало что может предложить для iOS. Но хорошо, что есть Xcode, который упрощает задачу и поскольку XCode управляет обеспечивающими профилями непосредственно через iTunes Connect, он стал наиболее вероятно предпочтительным решением независимо от того, как Ionic относится к этому.
Вывод
Так, после ожидания неприлично долгого процесса рассмотрения Apple у нас было два готовых приложения, и потребовалось не больше, чем 10 рабочих дней, чтобы их закончить.
Это довольно впечатляющее и намного более быстрое, чем какое-либо из предыдущих приложений, о которых мы когда-либо говорили. А теперь вопрос – станет ли Ionic нашим новый фреймворком по умолчанию для приложений? Скорее всего, да. Вот то, что мы вынесли для себя и что мы думаем о гибридных приложениях, сравнивая их с исходными (родными) приложениями:
Работа
Несмотря на то, что наше приложение работает очень хорошо, оно все еще использует переходы CSS3 и зависит от девайса пользователя в отличии от исходного приложения. Не так важно, но стоит отметить.
В целом, гибридные приложения все еще немного позади с точки зрения работы, но Ionic определенно проделал фантастическую работу и поэтому различие в работе будет незначительным.
Пользовательский опыт (ПО)
Это интересный момент: исходное приложение определенно имеет преимущество, когда дело доходит до создания платформы приложения, которое будет специфически выглядеть, но требования заказчика могут быть сложными для выполнения. С другой стороны, гибридные приложения легко выполнять под заказ, но задача становится намного сложней, когда нужно придать исходный вид и чувство от приложения.
Разработка
Работа над приложением приносила большое удовольствие, даже если сравнивать с очень хорошим Xcode. Время, которое уходит на то, чтобы собрать исходное приложение после каждого изменения кода, конечно, имеет большое значение и наши две недели растянулись бы еще больше, не говоря уже о Android SDK и Eclipse!
Обучение
Нет никаких сомнений в легкости обучения работе с AngularJS и Ionic framework. Это будет более легкой задачей для среднего веб-разработчика, чем обучение работе с Objective-C или Java, не говоря уже о том, что те же самые веб-технологии сработаются с любыми платформами, которые вы выберете для дальнейшего развития. Это большое преимущество, особенно в бизнесе, где приходится сталкиваться с изменениями в штате. По этой причине, в первую очередь, существуют гибридные приложения.