Статьи

Создайте мобильное приложение для отображения контента вашего сайта с помощью Ionic

Конечный продукт
Что вы будете создавать

В этом уроке мы рассмотрим создание мобильного приложения, которое отображает RSS-контент веб-сайта. Мы настроим URL-адрес RSS, и приложение загрузит его, проанализирует и отобразит сообщения из RSS.

Для создания мобильного приложения мы будем использовать Ionic Framework v1 вместе с AngularJS. Чтобы завершить этот урок, вы должны иметь некоторый опыт работы с JavaScript и HTML. Также полезно, если вы работали с AngularJS раньше.

Если вы никогда ранее не работали с Ionic Framework, я рекомендую хотя бы взглянуть на руководство « Приступая к работе», так как оно дает вам быстрое представление о том, как все работает.

Давайте начнем!

Я предполагаю, что вы установили Node в своей системе и у вас также есть npm (менеджер пакетов Node). Установка Ionic Framework так же проста, как запуск следующего:

1
npm install -g cordova ionic

Это установит Cordova и Ionic на ваш компьютер.

Cordova является основной технологией Ionic, и в основном она позволяет нам иметь встроенный браузер в нашем мобильном приложении. В этом браузере мы сможем запустить весь наш код HTML и JavaScript. Это называется гибридным мобильным приложением, поскольку приложение не запускает собственный код, а работает внутри браузера.

Помимо Cordova, Ionic добавляет к этому возможность использования AngularJS для написания нашего кода, а также добавляет очень аккуратный UI-фреймворк.

С Ionic на месте, мы можем создать наш проект, используя Ionic CLI, очень полезный инструмент командной строки. Ionic предоставляет три шаблона проекта по умолчанию, которые можно использовать в качестве отправной точки:

  • blank: как следует из названия, это пустой проект с минимально необходимыми компонентами.
  • вкладки: приложение, использующее вкладки для навигации по экранам.
  • sidemenu: приложение, использующее стандартное мобильное боковое меню для навигации.

Для этого урока мы будем использовать шаблон приложения с вкладками. Чтобы начать наш проект, давайте запустим:

1
ionic start myWebsiteOnMobile tabs

Ionic загрузит и установит все необходимые компоненты и создаст папку проекта с именем myWebsiteOnMobile . Перейдите в каталог проекта, выполнив:

1
cd myWebsiteOnMobile

Поскольку наше приложение является гибридным мобильным приложением, мы имеем преимущество в том, что можем запускать приложение в браузере. Для этого Ionic предоставляет аккуратный встроенный веб-сервер, который запускает наше приложение следующим образом:

1
ionic serve

Это откроет браузер с загруженным нашим приложением и будет выглядеть так:

Ionic домашний экран

Чтобы остановить сервер, используйте Control-C на экране командной строки. Чтобы лучше понять, как приложение выглядит на мобильном телефоне, вы можете использовать:

1
ionic serve —lab

Это откроет приложение в браузере, показывая iOS и предварительный просмотр приложения Android рядом друг с другом.

Предварительный просмотр iOS и Android

Вкладки Шаблон приложения Ionic имеет три вкладки: Статус, Чаты и Аккаунт. На следующих шагах мы настроим приложение в соответствии с нашими потребностями.

Для нашего приложения у нас будет две вкладки:

  • Последние сообщения: отображение списка последних сообщений, полученных из RSS-канала.
  • Настройки: где пользователь сможет настроить несколько аспектов приложения.

На вкладке «Последние сообщения» пользователь сможет щелкнуть любое из последних сообщений и просмотреть дополнительную информацию о сообщении с возможностью открытия сообщения во внешнем браузере.

Поскольку наша вкладка «Последние сообщения» аналогична вкладке «Чаты», предоставляемой шаблоном, мы будем использовать ее вместе с вкладкой «Аккаунт», которая станет нашей вкладкой «Настройки». Мы можем выполнить все модификации с запущенным веб-сервером Ionic, и Ionic перезагрузит приложение для нас. Это очень аккуратная функция, которая ускорит разработку.

Как упоминалось ранее, Ionic использует AngularJS, и все приложение фактически является модулем AngularJS. Модуль определен в www/js/app.js , и здесь также www/js/app.js пути или маршруты приложения. Каждый экран приложения имеет соответствующий маршрут.

Давайте удалим вкладку Статус, так как она нам не понадобится. Для этого сначала нужно изменить экран (или маршрут) нашего приложения по умолчанию, чтобы он указывал на экран чатов, который станет нашим основным экраном. Экран по умолчанию настраивается через $urlRouterProvider.otherwise() , поэтому давайте изменим его на:

1
$urlRouterProvider.otherwise(‘/tab/chats’);

Если мы теперь перезагрузим http://localhost:8100 в нашем браузере, мы увидим, что вкладка Чаты будет загружена по умолчанию.

Чтобы удалить вкладку «Состояние», нам нужно отредактировать файл www/templates/tabs.html , содержащий шаблон для компонента вкладки. Мы удалим элемент:

1
2
3
4
<!— Dashboard Tab —>
 <ion-tab title=»Status» icon-off=»ion-ios-pulse» icon-on=»ion-ios-pulse-strong» href=»#/tab/dash»>
   <ion-nav-view name=»tab-dash»></ion-nav-view>
 </ion-tab>

При сохранении мы увидим, что приложение теперь имеет только две вкладки: Чаты и Аккаунт.

В файле www/templates/tabs.html мы заметили, что есть некоторые теги HTML, которые не являются стандартными HTML, такие как ion-tabs , ion-tab и ion-nav-view . На самом деле это директивы AngularJS, определенные Ionic Framework. Директивы представляют собой теги, которые упаковывают функциональность за ними, и они являются очень удобными способами написания более структурированного и более лаконичного кода.

В нашем случае директива ion-tabs является компонентом tabs, который для каждой вкладки требует директивы ion-tabs .

Давайте изменим наши вкладки с чата и учетной записи на наши необходимые имена Последние сообщения и настройки. Для этого мы www/templates/tabs.html несколько вещей в файле www/templates/tabs.html :

  • Атрибут title элементов ion-tab определяющий текст на кнопке tab. Мы изменим это на Последние сообщения и Настройки соответственно.
  • Атрибут href элементов ion-tab который указывает на маршрут или URL экрана. Мы изменим их на #/tab/latest-posts и #/tab/settings .
  • Атрибут name элементов ion-nav-view для tab-latest-posts и tab-settings . Это идентификаторы для шаблонов представления, используемых для последних сообщений и экранов настроек.

В результате, www/templates/tabs.html должен выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<ion-tabs class=»tabs-icon-top tabs-color-active-positive»>
 
  <!— Latest posts Tab —>
  <ion-tab title=»Latest posts» icon-off=»ion-ios-chatboxes-outline» icon-on=»ion-ios-chatboxes» href=»#/tab/latest-posts»>
    <ion-nav-view name=»tab-latest-posts»></ion-nav-view>
  </ion-tab>
 
  <!— Settings Tab —>
  <ion-tab title=»Settings» icon-off=»ion-ios-gear-outline» icon-on=»ion-ios-gear» href=»#/tab/settings»>
    <ion-nav-view name=»tab-settings»></ion-nav-view>
  </ion-tab>
 
 
</ion-tabs>

После внесения этих изменений мы получим некоторые ошибки. Это потому, что мы также должны настроить наши маршруты, чтобы использовать новые идентификаторы, которые мы использовали. В www/js/app.js нам нужно изменить идентификаторы состояния, идентификаторы представления и url для каждого маршрута в соответствии с тем, что мы установили выше.

Для каждого маршрута (или экрана) определен контроллер. Это базовый шаблон проектирования MVC (Model-View-Controller). Контроллеры определены в файле www/js/controllers.js . В целях обеспечения согласованности мы изменим имена контроллеров как в www/js/app.js и в www/js/controller.js :

  • ChatsCtrl становится ChatsCtrl .
  • 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 файл www/js/app.js который выглядит следующим образом:

01
02
03
04
05
06
07
08
09
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
// Each tab has its own nav history stack:
 
  .state(‘tab.latest-posts’, {
      url: ‘/latest-posts’,
      views: {
        ‘tab-latest-posts’: {
          templateUrl: ‘templates/tab-latest-posts.html’,
          controller: ‘LatestPostsCtrl’
        }
      }
    })
    .state(‘tab.post-detail’, {
      url: ‘/latest-posts/:postId’,
      views: {
        ‘tab-latest-posts’: {
          templateUrl: ‘templates/post-detail.html’,
          controller: ‘PostDetailCtrl’
        }
      }
    })
 
  .state(‘tab.settings’, {
    url: ‘/settings’,
    views: {
      ‘tab-settings’: {
        templateUrl: ‘templates/tab-settings.html’,
        controller: ‘SettingsCtrl’
      }
    }
  });
 
  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise(‘/tab/latest-posts’);
  …

И наш очищенный файл www/js/controllers.js выглядит так:

1
2
3
4
angular.module(‘starter.controllers’, [])
.controller(‘LatestPostsCtrl’, function($scope) {})
.controller(‘PostDetailCtrl’, function($scope, $stateParams) {})
.controller(‘SettingsCtrl’, function($scope) {});

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

Чтобы отобразить список последних сообщений, нашему приложению потребуется извлечь RSS-канал с URL-адреса. Рекомендуется, чтобы такая функциональность находилась на уровне обслуживания приложения. Таким образом, мы можем легче использовать его в нашем контроллере, а затем представить его пользователю с помощью представления.

Служба RSS будет использовать YQL REST API от Yahoo для получения RSS нашего сайта. Для вызова REST API мы будем использовать поставщика $http , предлагаемого AngularJS.

Ионные сервисы обычно определяются в файле www/js/services.js , так что мы также разместим наши. Код будет выглядеть так:

01
02
03
04
05
06
07
08
09
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
43
44
45
46
47
48
49
50
51
angular.module(‘starter.services’, [])
.service(‘RSS’,function($http){
  var self = this;
  this.download = function(next){
    var feedUrl = «https://tutorials.tutsplus.com/posts.atom»;
    var yql_query = «select * from xml where url = ‘»+feedUrl+»‘»;
    var url = ‘https://query.yahooapis.com/v1/public/yql?q=’+encodeURIComponent(yql_query)+’&format=json&callback=JSON_CALLBACK’;
    $http
      .jsonp(url)
      .success(function(response){
        if (response.query.results[«feed»]){
          next(self.parseAtom(response.query.results));
        } else if (response.query.results[«rss»]){
          next(self.parseRSS(response.query.results));
        } else {
          throw «Unknown RSS format»;
        }
      })
      .error(function(data, status){
 
      });
  }
 
  this.parseAtom = function(atomFeed){
    var posts = [];
    angular.forEach(atomFeed.feed.entry,function(item,idx){
      var post = {
        id:idx,
        title:item.title,
        description:item.content.content,
        link:item.link.href
      }
      posts.push(post);
    })
    return posts;
  }
 
  this.parseRSS = function(rssFeed){
    var posts = [];
    angular.forEach(rssFeed.rss.channel.item,function(item,idx){
      var post = {
        id:idx,
        title:item.title,
        description:item.description,
        link:item.link
      }
      posts.push(post);
    })
    return posts;
  }
})

Мы объявляем службу, используя метод service() предоставляемый AngularJS. Затем мы вводим модуль $http Angular, чтобы мы могли вызывать его в нашем сервисе.

Переменная self является ссылкой на службу RSS, поэтому мы можем вызывать ее из методов службы. Основным методом службы является метод download() , который загружает информацию канала и обрабатывает ее. Существует два основных формата, используемых для веб-каналов: RSS и ATOM. Для нашего приложения мы использовали ленту учебников из Tuts + https://tutorials.tutsplus.com/posts.atom, которая находится в формате ATOM, но для полноты картины мы также приняли во внимание формат RSS.

Метод download() вызывает API-интерфейс YQL и анализирует результаты, используя parseAtom() или parseRSS() зависимости от типа канала. Идея здесь состоит в том, чтобы иметь тот же формат вывода, который будет передан через обратный вызов next() . С сервисом RSS на месте, мы можем перейти к контроллеру.

В нашем файле www/js/controllers.js нам нужно загрузить данные RSS и передать их нашему представлению. Для этого нам нужно только изменить наш контроллер LatestPostsCtrl следующим образом:

1
2
3
4
5
.controller(‘LatestPostsCtrl’, function($scope, RSS) {
  RSS.download(function(posts){
    $scope.posts = posts;
  });
})

Используя механизм внедрения зависимостей Angular, нам нужно только указать переменные $scope и RSS качестве параметров метода, и он будет знать, как загрузить эти модули. Модуль $scope позволяет нам устанавливать переменные в модели, связанной с представлением. Любые значения, установленные в области, могут быть затем извлечены и отображены в представлении, связанном с контроллером.

Когда представление для последних сообщений загружается, он вызывает контроллер LatestPostsCtrl , который, в свою очередь, использует службу RSS для загрузки информации о фиде. Результаты анализируются и передаются обратно в виде массива с помощью переменной posts , которую мы храним в текущей области видимости.

После всего этого мы можем перейти к представлению, отображающему список сообщений, полученных из канала.

Теперь нам нужно изменить наш взгляд на последние сообщения. Если вы помните, это настраивается в файле www/js/app.js через атрибут templateUrl и указывает на файл www/templates/tab-latest-posts.html .

Что мы хотим сделать, это отобразить список каналов. Поскольку информация о фиде может содержать HTML, и это будет только загромождать список последних сообщений, нам нужно что-то извлечь из тега содержимого без тегов HTML. Самый простой способ сделать это — определить фильтр AngularJS, который удаляет теги HTML из текста. Давайте сделаем это в www/js/services.js , добавив:

1
2
3
4
5
6
.filter(‘htmlToPlaintext’, function() {
    return function(text) {
      return text ?
    };
  }
)

Не вернемся к нашему представлению в файле www/templates/tab-latest-posts.html , давайте www/templates/tab-latest-posts.html его так:

01
02
03
04
05
06
07
08
09
10
11
12
<ion-view view-title=»Latest posts»>
  <ion-content>
    <ion-list>
      <ion-item class=»item-icon-left item-icon-right» ng-repeat=»post in posts» type=»item-text-wrap» href=»#/tab/latest-posts/{{post.id}}»>
        <span class=»icon ion-social-rss-outline»>
        <h2>{{post.title}}</h2>
        <p>{{post.description |
        <i class=»icon ion-chevron-right icon-accessory»></i>
      </ion-item>
    </ion-list>
  </ion-content>
</ion-view>

Мы используем компонент пользовательского интерфейса Ionic list вместе с директивой Angular ng-repeat , которая будет перебирать posts установленные в области действия нашего контроллера. Для каждой записи поста у нас будет элемент списка с его заголовком и описанием, очищенным от тегов HTML с помощью фильтра htmlToPlaintext . Также обратите внимание, что нажатие на сообщение должно привести нас к деталям сообщения из-за атрибута href установленного в #/tab/latest-posts/{{post.id}} . Это пока не работает, но мы позаботимся об этом в следующем разделе.

Если мы теперь запустим приложение, используя ionic serve --lab , мы должны получить что-то вроде этого:

Просмотр последних сообщений

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

Чтобы решить эту проблему, мы можем использовать директиву $rootScope предлагаемую Angular. Это относится к области действия, которая охватывает все контроллеры в приложении. Давайте $rootScope наш LatestPostCtrl чтобы установить сообщения в $rootScope а затем $rootScope поиск определенного сообщения, которое пользователь щелкнул в PostDetailCtrl . Результирующий код в www/js/controllers.js будет выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
.controller(‘LatestPostsCtrl’, function($scope, $rootScope, RSS) {
  RSS.download(function(posts){
    $rootScope.posts = posts;
  });
})
 
.controller(‘PostDetailCtrl’, function($scope,$rootScope, $stateParams) {
  angular.forEach($rootScope.posts,function(post){
    if (post.id == $stateParams.postId){
      $scope.post = post;
    }
  })
})

Мы просто ввели $rootScope в оба контроллера и использовали его для передачи posts между двумя контроллерами. Обратите внимание, что нам не нужно вносить какие-либо изменения в наше последнее представление сообщений, так как $rootScope и $scope оба доступны одинаково из представления.

Внутри контроллера PostDetailCtrl мы просто ищем пост с идентификатором, переданным в ссылке, по которой щелкнул пользователь. Мы делаем это, сравнивая каждый идентификатор сообщения со значением в URL, передаваемом через переменную $stateParams.postId . Если мы найдем совпадение, мы установим сообщение в области видимости, чтобы мы могли использовать его в нашем представлении.

Давайте теперь настроим наш подробный вид поста www/templates/post-detail.html следующим образом:

01
02
03
04
05
06
07
08
09
10
11
<ion-view view-title=»{{post.title}}»>
  <ion-nav-buttons side=»right»>
    <a ng-href=»{{post.link}}» class=»button» target=»_system»>
      Open
    </a>
  </ion-nav-buttons>
  <ion-content class=»padding»>
    <h1>{{post.title}}</h1>
    <span ng-bind-html=»post.description»>
  </ion-content>
</ion-view>

Это то, что мы сделали в представлении:

  • Мы поместили заголовок поста в заголовок экрана.
  • Мы поместили кнопку «Открыть» в заголовке справа. Эта кнопка откроет ссылку на публикацию во внешнем браузере из-за атрибута target="_system" . Мы должны сделать это, потому что приложение уже запущено в браузере из-за Cordova. Если бы мы не установили этот атрибут, публикация открылась бы в том же браузере, что и приложение, и тогда у нас не было бы способа вернуться в приложение.
  • Мы выводим описание поста в виде HTML с помощью директивы Angular ng-bind-html .

Во время работы приложения я заметил, что если описание поста содержит изображения, некоторые из них выпадают из экрана. Это может быть в случае с другими элементами HTML, такими как видео. Мы можем легко это исправить, добавив следующее правило CSS в www/css/style.css .

1
2
3
ion-content *{
    max-width: 100%;
}

Если мы сейчас посмотрим на приложение и нажмем на одну из публикаций, мы должны увидеть что-то вроде этого:

Просмотр постов к статьям Tuts

И наше приложение почти завершено. В следующем разделе мы рассмотрим реализацию экрана настроек.

Для нашего экрана настроек мы реализуем способ указания количества сообщений, отображаемых на главном экране приложения. Мы сохраним этот параметр в памяти localStorage , которая не стирается при закрытии приложения. Давайте отредактируем файл контроллеров www/js/controllers.js и изменим контроллер SettingsCtrl следующим образом:

01
02
03
04
05
06
07
08
09
10
.controller(‘SettingsCtrl’, function($scope,$rootScope) {
  $scope.settings = {
    maxPosts: window.localStorage.getItem(«myWebsiteOnMobile.maxPosts»)
  };
 
  $scope.$watch(‘settings.maxPosts’,function(){
    window.localStorage.setItem(«myWebsiteOnMobile.maxPosts»,$scope.settings.maxPosts);
    $rootScope.maxPosts = window.localStorage.getItem(«myWebsiteOnMobile.maxPosts»);
  });
});

Также нам нужно изменить экран настроек в www/templates/tab-settings.html следующим образом:

1
2
3
4
5
6
7
8
<ion-view view-title=»Settings»>
  <ion-content>
      <div class=»item item-divider item-balanced»>Maximum posts</div>
    <ion-radio ng-model=»settings.maxPosts» ng-value=»null»>Unlimited</ion-radio>
    <ion-radio ng-model=»settings.maxPosts» ng-value=»5″>5</ion-radio>
    <ion-radio ng-model=»settings.maxPosts» ng-value=»10″>10</ion-radio>
  </ion-content>
</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}}»>

Обратите внимание на limitTo:maxPosts Угловой фильтр. Это ограничит количество отображаемых сообщений числом, взятым из localStorage . По умолчанию это будет null , который будет отображать все каналы, полученные службой RSS.

Поздравляем! Теперь у нас есть полностью работающее приложение, отображающее RSS-канал.

В этом руководстве мы увидели, как создать гибридное мобильное приложение с использованием Ionic Framework и AngularJS. Осталось сделать только одно: запустить приложение на мобильном устройстве или в мобильном эмуляторе. Это очень просто с Ionic. Чтобы запустить приложение на эмуляторе Android, просто запустите:

1
2
ionic platform add android
ionic run

Если вы хотите загрузить готовый шаблон приложения Ionic для преобразования любого веб-сайта в мобильное приложение, попробуйте перейти на веб-сайт в шаблон приложения Mobile Ionic из CodeCanyon.

Шаблон приложения на CodeCanyon