Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)



В этом уроке мы рассмотрим создание мобильного приложения, которое отображает RSS-содержимое веб-сайта. Мы настроим URL-адрес RSS, и приложение загрузит его, проанализирует и отобразит сообщения из RSS.
Чтобы создать мобильное приложение, мы будем использовать Ionic Framework v1 вместе с AngularJS. Чтобы завершить этот урок, вам нужно иметь некоторый опыт работы с JavaScript и HTML. Кроме того, будет полезно, если вы раньше работали с AngularJS.
Если вы никогда раньше не работали с Ionic Framework, я рекомендую по крайней мере взглянуть на руководство для начинающих, поскольку оно даст вам краткое представление о том, как все работает.
Давайте начнем!
Настройка проекта Ionic
Я предполагаю, что вы установили Node в свою систему, и у вас также есть npm (менеджер пакетов Node). Установка Ionic-фреймворка очень простая:
1 |
npm install -g cordova ionic |
Это установит на вашем компьютере как Cordova, так и Ionic.
Cordova является основной технологией для Ionic, и в основном это позволяет нам получить встроенный браузер в нашем мобильном приложении. В этом браузере мы сможем запустить весь наш код HTML и JavaScript. Это называется гибридным мобильным приложением, поскольку приложение не запускает собственный код, но работает внутри браузера.
Так же Ionic имеет возможность использования AngularJS для написания нашего кода, а также имеет очень приятный UI фреймворк.
Используя Ionic, мы можем создать наш проект с использованием Ionic CLI, очень полезного инструмента командной строки. Ionic предоставляет три шаблона проекта по умолчанию, которые можно использовать в качестве отправной точки:
- blank: судя из названи], это пустой проект с минимальными необходимыми компонентами.
- tabs: приложение, использующее вкладки для навигации по экранам.
- sidemenu: приложение, использующее стандартное мобильное боковое меню для навигации.
Для этого урока мы будем использовать шаблон приложения табуляции. Чтобы запустить наш проект, давайте выполним следующее:
1 |
ionic start myWebsiteOnMobile tabs |
Ionic загрузит и установит все необходимые компоненты, и создаст папку проекта с именем myWebsiteOnMobile
. Перейдите в каталог проекта, выполнив:
1 |
cd myWebsiteOnMobile
|
Поскольку наше приложение представляет собой гибридное мобильное приложение, у нас есть преимущество, заключающееся в возможности запуска приложения внутри браузера. Для этого Ionic предоставляет аккуратный встроенный веб-сервер, который запускает наше приложение следующим образом:
1 |
ionic serve |
Это откроет браузер с загруженным приложением, и он будет выглядеть следующим образом:



Чтобы остановить сервер, используйте Control-C на экране командной строки. Чтобы лучше понять, как приложение выглядит на мобильном устройстве, вы можете использовать:
1 |
ionic serve --lab
|
Это откроет приложение в браузере, показывая рядом iOS и Android-версию приложения.



Шаблон Ionic для вкладок содержит три вкладки: статус, чаты и учетная запись. В последующих шагах мы будем корректировать приложение в соответствии с нашими потребностями.
Как настроить шаблон приложения Ionic Tab
Для нашего приложения у нас будет две вкладки:
- Последние сообщения: показ списка последних сообщений, полученных из RSS-канала.
- Настройки: где пользователь сможет настроить несколько аспектов приложения.
На вкладке «Последние сообщения» пользователь сможет щелкнуть любое из последних сообщений и просмотреть дополнительную информацию о сообщении, с возможностью открытия сообщения во внешнем браузере.
Поскольку вкладка «Последние сообщения» аналогична вкладке «Чаты», предоставленной шаблоном, мы будем использовать ее вместе со вкладкой «Учетная запись», которая станет вкладкой «Настройки». Мы можем делать все изменения с помощью Ionic webserver, и Ionic перезагрузит приложение для нас. Это очень удобная функция, которая ускорит разработку.
Как упоминалось ранее, Ionic использует AngularJS, и все приложение на самом деле является модулем AngularJS. Модуль определен в www/js/app.js
, и здесь также определяются пути или маршруты приложения. Каждый экран приложения имеет соответствующий маршрут.
Удалим вкладку «Состояние», так как она нам не понадобится. Для этого сначала нужно изменить экран (или маршрут) по умолчанию нашего приложения, чтобы указать на экран чатов, который станет нашим основным экраном. Экран по умолчанию настроен через $urlRouterProvider.otherwise()
, поэтому давайте изменим его на:
1 |
$urlRouterProvider.otherwise('/tab/chats'); |
Если мы сейчас перезагружаем http://localhost:8100
в вашем браузере, мы увидим, что вкладка Чаты будет загружена по умолчанию.
Чтобы удалить вкладку «Состояние», нам необходимо отредактировать файл www/templates/tabs.html
, содержащий шаблон для компонента вкладки. Мы удалим элемент:
1 |
<!-- Dashboard Tab -->
|
2 |
<ion-tab title="Status" icon-off="ion-ios-pulse" icon-on="ion-ios-pulse-strong" href="#/tab/dash"> |
3 |
<ion-nav-view name="tab-dash"></ion-nav-view> |
4 |
</ion-tab>
|
При сохранении мы увидим, что приложение теперь имеет только две вкладки: чаты и учетная запись.
В файле www/templates/tabs.html
мы замечаем, что есть некоторые HTML-теги, которые не являются стандартными HTML, такие как ion-tabs
, ion-tab
, and ion-nav-view
. На самом деле это директивы AngularJS, определенные в фреймворке Ionic. Директивы - это теги, которые устанавливают функциональность позади них, и они очень удобны для написания более структурированного и более сжатого кода.
В нашем случае директива ion-tabs
представляет собой компонент вкладок, который для каждой вкладки подключает директивы ion-tab
.
Давайте изменим наши вкладки из чата и учетной записи на соответствующие имена. Последние сообщения и настройки. Чтобы сделать это, мы изменим несколько вещей в файле www/templates/tabs.html
:
- Атрибут
title
элементовion-tab
определяет текст на кнопке вкладки. Мы изменим их на Последние сообщения и Настройки соответственно. - Атрибуты
href
элементовion-tab
указывают на маршрут или URL-адрес экрана. Мы изменим их на#/tab/latest-posts
и#/tab/settings
. - Атрибут
name
элементовion-nav-view
наtab-latest-posts
иtab-settings
. Это идентификаторы шаблонов представлений, используемые для экранов «Последние сообщения» и «Настройки».
В результате файл www/templates/tabs.html
должен выглядеть следующим образом:
1 |
<ion-tabs class="tabs-icon-top tabs-color-active-positive"> |
2 |
|
3 |
<!-- Latest posts Tab -->
|
4 |
<ion-tab title="Latest posts" icon-off="ion-ios-chatboxes-outline" icon-on="ion-ios-chatboxes" href="#/tab/latest-posts"> |
5 |
<ion-nav-view name="tab-latest-posts"></ion-nav-view> |
6 |
</ion-tab>
|
7 |
|
8 |
<!-- Settings Tab -->
|
9 |
<ion-tab title="Settings" icon-off="ion-ios-gear-outline" icon-on="ion-ios-gear" href="#/tab/settings"> |
10 |
<ion-nav-view name="tab-settings"></ion-nav-view> |
11 |
</ion-tab>
|
12 |
|
13 |
|
14 |
</ion-tabs>
|
После внесения этих изменений мы получим некоторые ошибки. Это связано с тем, что нам также необходимо настроить наши маршруты для использования новых идентификаторов, которые мы использовали. В www/js/app.js
нам нужно изменить идентификаторы состояний, идентификаторы вида и url
для каждого маршрута в соответствии с тем, что мы установили выше.
Для каждого маршрута (или экрана) определен свой контроллер. Это базовый шаблон проектирования MVC (Model-View-Controller). Контроллеры определяются в файле www/js/controllerlers.js
. Для целей согласования мы будем изменять имена контроллеров как в www/js/app.js
, так и в www/js/controller.js
:
-
ChatsCtrl
становитсяLastPostsCtrl
. -
ChatDetailCtrl
становитсяPostDetailCtrl
. -
AccountCtrl
становитсяSettingsCtrl
.
Кроме того, для каждого маршрута мы определяем шаблон вида, поэтому давайте тоже изменим их. Отредактируйте www/js/app.js
и измените templateUrl
следующим образом:
- Измените
tab-chats.html
наtab-latest-posts.html
. Также переименуйте файлwww/templates/tab-chats.html
вwww/templates/tab-latest-posts.html
. - Измените
chat-detail.html
наpost-detail.html
. Также переименуйте файлwww/templates/chat-detail.html
вwww/templates/post-detail.html
. - Измените
tab-account.html
наtab-settings.html
. Также переименуйте файлwww/templates/tab-account.html
вwww/templates/tab-settings.html
. - Наконец, измените представление, которое по умолчанию загружается в
latest-posts
, используя$urlRouterProvider.otherwise('/tab/latest-posts')
.
Если все пойдет хорошо, вы должны получить файл www/js/app.js
, выглядящий следующим образом:
1 |
...
|
2 |
// Each tab has its own nav history stack:
|
3 |
|
4 |
.state('tab.latest-posts', { |
5 |
url: '/latest-posts', |
6 |
views: { |
7 |
'tab-latest-posts': { |
8 |
templateUrl: 'templates/tab-latest-posts.html', |
9 |
controller: 'LatestPostsCtrl' |
10 |
}
|
11 |
}
|
12 |
})
|
13 |
.state('tab.post-detail', { |
14 |
url: '/latest-posts/:postId', |
15 |
views: { |
16 |
'tab-latest-posts': { |
17 |
templateUrl: 'templates/post-detail.html', |
18 |
controller: 'PostDetailCtrl' |
19 |
}
|
20 |
}
|
21 |
})
|
22 |
|
23 |
.state('tab.settings', { |
24 |
url: '/settings', |
25 |
views: { |
26 |
'tab-settings': { |
27 |
templateUrl: 'templates/tab-settings.html', |
28 |
controller: 'SettingsCtrl' |
29 |
}
|
30 |
}
|
31 |
});
|
32 |
|
33 |
// if none of the above states are matched, use this as the fallback
|
34 |
$urlRouterProvider.otherwise('/tab/latest-posts'); |
35 |
...
|
И наш очищенный файл www/js/controllers.js
теперь выглядит следующим образом:
1 |
angular.module('starter.controllers', []) |
2 |
.controller('LatestPostsCtrl', function($scope) {}) |
3 |
.controller('PostDetailCtrl', function($scope, $stateParams) {}) |
4 |
.controller('SettingsCtrl', function($scope) {}); |
Теперь, когда мы изменили приложение в соответствии с нашими потребностями, перейдем к следующей части и добавим некоторые функции.
Как получить RSS-канал с помощью Ionic
Чтобы отобразить список последних сообщений, наше приложение должно будет получить RSS-канал из URL-адреса. В качестве наилучшей практики желательно, чтобы такая функциональность находилась на уровне обслуживания приложения. Таким образом, мы можем использовать его более легко в нашем контроллере, а затем представить его пользователю с помощью представления.
Служба RSS будет использовать YQL REST API Yahoo для извлечения RSS нашего сайта. Чтобы вызвать API REST, мы будем использовать провайдер $http
, предоставляемый в AngularJS.
Ionic службы обычно определяются в файле www/js/services.js
, поэтому мы также будем размещать и наши. Код будет выглядеть так:
1 |
angular.module('starter.services', []) |
2 |
.service('RSS',function($http){ |
3 |
var self = this; |
4 |
this.download = function(next){ |
5 |
var feedUrl = "https://tutsplus.com/posts.atom"; |
6 |
var yql_query = "select * from xml where url = '"+feedUrl+"'"; |
7 |
var url = 'https://query.yahooapis.com/v1/public/yql?q='+encodeURIComponent(yql_query)+'&format=json&callback=JSON_CALLBACK'; |
8 |
$http
|
9 |
.jsonp(url) |
10 |
.success(function(response){ |
11 |
if (response.query.results["feed"]){ |
12 |
next(self.parseAtom(response.query.results)); |
13 |
} else if (response.query.results["rss"]){ |
14 |
next(self.parseRSS(response.query.results)); |
15 |
} else { |
16 |
throw "Unknown RSS format"; |
17 |
}
|
18 |
})
|
19 |
.error(function(data, status){ |
20 |
|
21 |
});
|
22 |
}
|
23 |
|
24 |
this.parseAtom = function(atomFeed){ |
25 |
var posts = []; |
26 |
angular.forEach(atomFeed.feed.entry,function(item,idx){ |
27 |
var post = { |
28 |
id:idx, |
29 |
title:item.title, |
30 |
description:item.content.content, |
31 |
link:item.link.href |
32 |
}
|
33 |
posts.push(post); |
34 |
})
|
35 |
return posts; |
36 |
}
|
37 |
|
38 |
this.parseRSS = function(rssFeed){ |
39 |
var posts = []; |
40 |
angular.forEach(rssFeed.rss.channel.item,function(item,idx){ |
41 |
var post = { |
42 |
id:idx, |
43 |
title:item.title, |
44 |
description:item.description, |
45 |
link:item.link |
46 |
}
|
47 |
posts.push(post); |
48 |
})
|
49 |
return posts; |
50 |
}
|
51 |
})
|
Мы объявляем сервис, используя метод service()
, предоставляемый AngularJS. Затем мы внедрядем модуль Angular $http
, чтобы мы могли его назвать в нашем сервисе.
Переменная self
является ссылкой на службу RSS, чтобы мы могли ее вызвать из методов службы. Основным методом службы является метод download()
, который загружает информацию о фиде и обрабатывает его. Существуют два основных формата, используемых для фидов веб-сайтов: RSS и ATOM. Для нашего приложения мы использовали фид учебников от Tuts + https://tutsplus.com/posts.atom, который находится в формате ATOM, но для полноты мы также учли формат RSS.
Метод download()
вызывает API YQL и анализирует результаты с использованием методов parseAtom()
или parseRSS()
в зависимости от типа фида. Идея здесь состоит в том, чтобы иметь тот же формат вывода, который будет передан далее через обратный вызов next()
. С помощью службы RSS мы можем перейти к контроллеру.
Подключение службы RSS к контроллеру последних сообщений
В нашем файле www/js/controllers.js
нам нужно загрузить данные RSS и передать их нашему представлению. Для этого нам нужно только изменить наш контроллер NewPostsCtrl
следующим образом:
1 |
.controller('LatestPostsCtrl', function($scope, RSS) { |
2 |
RSS.download(function(posts){ |
3 |
$scope.posts = posts; |
4 |
});
|
5 |
})
|
Используя механизм инъекции зависимости, нам нужно только указать переменные $scope
и RSS
как параметры метода, и он будет знать, как загрузить эти модули. Модуль $scope
позволяет нам устанавливать переменные на модели, связанной с представлением. Любые значения, установленные в scope, могут быть затем извлечены и отображены внутри представления, связанного с контроллером.
Когда загружается представление для последних сообщений, оно будет вызывать контроллер LatestPostsCtrl
, и он, в свою очередь, будет использовать службу RSS для загрузки информации о фиде. Результаты анализируются и передаются в виде массива с использованием переменной posts
, которую мы сохраняем в текущем scope.
Теперь мы можем перейти к части представления, отображая список сообщений, полученных из фида.
Передача данных о последних сообщениях в отображение
Теперь нам нужно изменить наше отображение для последних сообщений. Если вы помните, оно настроено в файле www/js/app.js
через атрибут templateUrl
, и который указывает на файл www/templates/tab-latestposts.html
.
Нам нужно будет отобразить список фидов. Поскольку информация фида может содержать HTML, и это будет только загромождать список последних сообщений, нам нужно как-то извлечь текст без тегов HTML из содержимого сообщения. Самый простой способ сделать это - определить фильтр AngularJS, который удаляет теги HTML из текста. Давайте сделаем это в www/js/services.js
, добавив следующее:
1 |
.filter('htmlToPlaintext', function() { |
2 |
return function(text) { |
3 |
return text ? String(text).replace(/<[^>]+>/gm, '') : ''; |
4 |
};
|
5 |
}
|
6 |
)
|
Теперь вернемся к нашему представлению в файле www/templates/tab-latest-posts.html
, давайте изменим его, чтобы оно выглядело так:
1 |
<ion-view view-title="Latest posts"> |
2 |
<ion-content>
|
3 |
<ion-list>
|
4 |
<ion-item class="item-icon-left item-icon-right" ng-repeat="post in posts" type="item-text-wrap" href="#/tab/latest-posts/{{post.id}}"> |
5 |
<span class="icon ion-social-rss-outline"></span> |
6 |
<h2>{{post.title}}</h2> |
7 |
<p>{{post.description | htmlToPlaintext}}</p> |
8 |
<i class="icon ion-chevron-right icon-accessory"></i> |
9 |
</ion-item>
|
10 |
</ion-list>
|
11 |
</ion-content>
|
12 |
</ion-view>
|
Мы используем компонент Ionic list UI вместе с директивой Angular ng-repeat
, которая будет проходить через все posts
, установленные в scope нашего контроллера. Для каждой записи у нас будет элемент списка с его названием и с описанием, лишенным HTML-тегов, с помощью фильтра htmlToPlaintext
. Также обратите внимание, что нажатие сообщения должно привести нас к деталям сообщения благодаря атрибуту href
, установленного на #/tab/latest-posts/{{post.id}}
. Это пока не работает, но мы позаботимся об этом в следующем разделе.
Если мы теперь запустим приложение с помощью ionic serve --lab
мы должны получить что-то вроде этого:



Отображение сведений о сообщении
При нажатии на сообщение в списке мы переходим на экран сведений о сообщении. Поскольку на каждом экране приложения есть свой собственный контроллер и, следовательно, его собственная область, мы не можем получить доступ к списку сообщений, чтобы отобразить конкретную запись. Мы снова можем вызвать службу RSS, но это будет неэффективно.
Чтобы решить эту проблему, мы можем использовать директиву $rootScope
, предлагаемую Angular. Она ссылается на область, которая доступна во всех контроллерах приложения. Давайте изменим наш LatestPostCtrl
, чтобы установить записи в $rootScope
, а затем выберем конкретную запись, которую пользователь нажал в PostDetailCtrl
. В результате код в www/js/controllerlers.js
будет выглядеть так:
1 |
.controller('LatestPostsCtrl', function($scope, $rootScope, RSS) { |
2 |
RSS.download(function(posts){ |
3 |
$rootScope.posts = posts; |
4 |
});
|
5 |
})
|
6 |
|
7 |
.controller('PostDetailCtrl', function($scope,$rootScope, $stateParams) { |
8 |
angular.forEach($rootScope.posts,function(post){ |
9 |
if (post.id == $stateParams.postId){ |
10 |
$scope.post = post; |
11 |
}
|
12 |
})
|
13 |
})
|
Мы просто встроили $rootScope
в оба контроллера и использовали его для передачи posts
между двумя контроллерами. Обратите внимание, что нам не нужно вносить какие-либо изменения в отображение последних сообщений, поскольку $rootScope
и $scope
оба доступны в отображении.
Внутри контроллера PostDetailCtrl мы просто ищем сообщение с идентификатором, переданным по ссылке, нажатой пользователем. Мы делаем это, сравнивая каждый идентификатор сообщения со значением в URL-адресе, передаваемом через переменную $stateParams.postId
. Если мы найдем совпадение, то мы поставим сообщение в scope, чтобы мы могли использовать его внутри отображения.
Теперь давайте отредактируем наш подробный вид сообщения в www/templates/post-detail.html
следующим образом:
1 |
<ion-view view-title="{{post.title}}"> |
2 |
<ion-nav-buttons side="right"> |
3 |
<a ng-href="{{post.link}}" class="button" target="_system"> |
4 |
Open |
5 |
</a>
|
6 |
</ion-nav-buttons>
|
7 |
<ion-content class="padding"> |
8 |
<h1>{{post.title}}</h1> |
9 |
<span ng-bind-html="post.description"></span> |
10 |
</ion-content>
|
11 |
</ion-view>
|
Это то, что мы сделали внутри отображения:
- Мы разместили заголовок сообщения в заголовке экрана.
- Мы поместили кнопку «Открыть» в заголовке справа. Эта кнопка откроет ссылку для связи во внешнем браузере благодаря атрибуту
target="_ system"
. Мы должны сделать это, потому что приложение уже работает в браузере из-за Cordova. Если бы мы не установили этот атрибут, сообщение открылось бы в том же браузере, что и само приложение, и тогда у нас не было бы способа вернуться назад к приложению. - Мы показываем описание сообщения как HTML, используя директиву Angular
ng-bind-html
.
При запуске приложения я заметил, что если описание сообщения содержит изображения, некоторые из них съезжают с экрана. Это может иметь место и с другими элементами HTML, такими как видео. Мы можем легко исправить это, добавив следующее правило CSS в www/css/style.css
.
1 |
ion-content *{ |
2 |
max-width: 100%; |
3 |
}
|
Если мы сейчас посмотрим на приложение и нажмем на одно из сообщений, мы увидим что-то вроде этого:



И наше приложение почти завершено. В следующем разделе мы рассмотрим реализацию экрана настроек.
Добавление настроек для нашего Ionic приложения
В нашем экране настроек мы укажем, сколько сообщений должно отображаться на главном экране приложения. Мы сохраним этот параметр в памяти localStorage
, которая не будет удалена, когда приложение будет закрыто. Давайте отредактируем файл контроллеров www/js/controllers.js
и изменим контроллер SettingsCtrl
следующим образом:
1 |
.controller('SettingsCtrl', function($scope,$rootScope) { |
2 |
$scope.settings = { |
3 |
maxPosts: window.localStorage.getItem("myWebsiteOnMobile.maxPosts") |
4 |
};
|
5 |
|
6 |
$scope.$watch('settings.maxPosts',function(){ |
7 |
window.localStorage.setItem("myWebsiteOnMobile.maxPosts",$scope.settings.maxPosts); |
8 |
$rootScope.maxPosts = window.localStorage.getItem("myWebsiteOnMobile.maxPosts"); |
9 |
});
|
10 |
});
|
Кроме того, нам нужно изменить экран настроек в www/templates/tab-settings.html
следующим образом:
1 |
<ion-view view-title="Settings"> |
2 |
<ion-content>
|
3 |
<div class="item item-divider item-balanced">Maximum posts</div> |
4 |
<ion-radio ng-model="settings.maxPosts" ng-value="null">Unlimited</ion-radio> |
5 |
<ion-radio ng-model="settings.maxPosts" ng-value="5">5</ion-radio> |
6 |
<ion-radio ng-model="settings.maxPosts" ng-value="10">10</ion-radio> |
7 |
</ion-content>
|
8 |
</ion-view>
|
Контроллер извлекает настройки myWebsiteOnMobile.maxPosts
из localStorage
. Если его не существует, он будет равен null
, и мы будем считать, что нет предела для максимального количества сообщений.
Мы вызываем метод $scope.$watch()
для контроля изменений параметра settings.maxPosts
, который привязан к радио контроллеру на экране настроек.
Каждый раз, когда мы меняем максимальное количество сообщений на экране настроек, этот параметр будет сохранен в localStorage
, и он будет извлечен оттуда, когда приложение перезагрузится.
Теперь давайте использовать эту настройку. Это очень просто, нужно добавить это в LatestPostsCtrl
из www/js/controllers.js
:
1 |
$rootScope.maxPosts = window.localStorage.getItem("myWebsiteOnMobile.maxPosts"); |
И добавим директиву на экран с последними сообщениями www/templates/tab-latest-posts.html
:
1 |
<ion-item class="item-icon-left item-icon-right" ng-repeat="post in posts|limitTo:maxPosts" type="item-text-wrap" href="#/tab/latest-posts/{{post.id}}"> |
Обратите внимание на фильтр Angualr limitTo:maxPosts
. Это ограничит количество отображаемых сообщений на число, взятое из localStorage
. По умолчанию это будет null
, что в итоге отобразит все фиды, полученные службой RSS.
Поздравления! Теперь у нас есть полностью работающее приложение, отображающее RSS-канал.
Вывод
В этом уроке мы увидели, как создать гибридное мобильное приложение с использованием Ionic Framework и AngularJS. Осталось еще одно: запустить приложение на мобильном устройстве или мобильном эмуляторе. С Ionic это очень просто. Чтобы запустить приложение на эмуляторе Android, просто выполните:
1 |
ionic platform add android |
2 |
ionic run |
Если вы хотите загрузить готовый шаблон приложения Ionic для преобразования любого веб-сайта в мобильное приложение, попробуйте использовать Шаблон Веб-сайта для мобильного приложения Ionic от CodeCanyon.


