

От создания масштабируемых NoSQL баз данных до хранения файлов, отправки push-уведомлений и аналитики использования – Firebase прекрасный выбор для разработчиков, которые ищут решение для создания мобильных приложений.
В этом уроке мы сосредоточимся исключительно на базах данных Firebase и создадим очень простое Ionic-приложение для платформы iOS, которое позволяет нам выполнять операции CRUD (Create, Read, Update & Delete), предоставляемые пакетом AngularFire2.
Наше приложение будет управлять фильмами. У них есть такие параметры:
- Название фильма
- Классификация (возрастной рейтинг)
- Жанр
- Актеры/актрисы
- Аннотация
- Год выпуска
Ничего сложного, но достаточно для того, чтобы обеспечить нам работу с Firebase и AngularFire2.
Мы также будем использовать следующие функции Ionic/Angular:
- Formbuilder API
- UI-компоненты (всплывающие окна, карточки и кнопки)
К концу урока мы создадим такое приложение:
Теперь, когда мы знаем, чего стоит ожидать, давайте создадим себе среду в Firebase…
Работа с Firebase
Зайдите на сайт Firebase, и если вы уже зарегистрированы, зайдите в свой аккаунт (а если нет, то создайте его, это бесплатно!).
Затем вы увидите все ваши существующие проекты, которые выглядят примерно так:
Давайте создадим новый проект, нажав кнопку CREATE NEW PROJECT. Появится всплывающее окно, в котором нужно будет ввести название проекта и выбрать страну/регион.
Как только проект будет создан, вы можете выбрать, как добавить Firebase в ваше приложение, выбрав одну из опций:
- Добавить Firebase в ваше iOS-приложение
- Добавить Firebase в ваше Android-приложение
- Добавить Firebase в ваше веб-приложение
Выберите опцию Add Firebase to your web app, так как это даст нам необходимые конфигурационные значения для интеграции Firebase в наше Ionic-приложение, не зависящее от платформы (т.е. веб, iOS или Android):
В всплывающем окне скопируйте следующие конфигурационные ключи и значения:
- apiKey
- authDomain
- databaseURL
- storageBucket
- messagingSenderId
Скопируйте, но не меняйте эти значения, так как вы не сможете соединить свое приложение с Firebase без них:
Сохраните эти конфигурационные ключи/значения в текстовом файле (мы используем их, когда будем создавать наш Ionic-проект чуть позже). Теперь, когда у нас есть проект Firebase, мы можем начать создавать базу данных и импортировать в неё все необходимые данные.
Создание базы данных
Базу данных в Firebase можно создать двумя способами:
- Ручной ввод значений и добавление ключей через консоль базы данных Firebase
- Импорт файла JSON с предварительно структурированным и заполненным набором ключей и значений, которые будут представлять наш базу данных
Я всегда выбираю второй подход, так как это более быстро, просто, легко и эффективно, если речь идет об использовании баз Firebase/NoSQL.
В вашем любимом редакторе кода создайте следующую JSON-структуру:
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
<span class="token punctuation">{</span> <span class="token string">"films"</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token string">"title"</span> <span class="token punctuation">:</span> <span class="token string">"John Wick"</span><span class="token punctuation">,</span> <span class="token string">"summary"</span><span class="token punctuation">:</span> <span class="token string">"Ex-assassin John Wick takes down the Russian Mafia in New York"</span><span class="token punctuation">,</span> <span class="token string">"date"</span> <span class="token punctuation">:</span> <span class="token string">"2014"</span><span class="token punctuation">,</span> <span class="token string">"duration"</span><span class="token punctuation">:</span> <span class="token string">"97 minutes"</span><span class="token punctuation">,</span> <span class="token string">"rating"</span><span class="token punctuation">:</span> <span class="token string">"15"</span><span class="token punctuation">,</span> <span class="token string">"cover"</span> <span class="token punctuation">:</span> <span class="token string">"none"</span><span class="token punctuation">,</span> <span class="token string">"actors"</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Keanu Reeves"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Willem Dafoe"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Michael Nyqvist"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Ian McShane"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"John Leguizamo"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Bridget Moynahan"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Alfie Allen"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Adrianne Palicki"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"genres"</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Action"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Thriller"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"title"</span> <span class="token punctuation">:</span> <span class="token string">"Gladiator"</span><span class="token punctuation">,</span> <span class="token string">"summary"</span><span class="token punctuation">:</span> <span class="token string">"The general who became a slave, the slave who became a gladiator, the gladiator who defied an empire"</span><span class="token punctuation">,</span> <span class="token string">"date"</span> <span class="token punctuation">:</span> <span class="token string">"2000"</span><span class="token punctuation">,</span> <span class="token string">"duration"</span><span class="token punctuation">:</span> <span class="token string">"2hr 29 minutes"</span><span class="token punctuation">,</span> <span class="token string">"rating"</span><span class="token punctuation">:</span> <span class="token string">"15"</span><span class="token punctuation">,</span> <span class="token string">"cover"</span> <span class="token punctuation">:</span> <span class="token string">"none"</span><span class="token punctuation">,</span> <span class="token string">"actors"</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Russell Crowe"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Oliver Reed"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Joaquin Phoenix"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Connie Nielsen"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Ralf Moeller"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"genres"</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Action"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Historical"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"title"</span> <span class="token punctuation">:</span> <span class="token string">"Catch me if you can"</span><span class="token punctuation">,</span> <span class="token string">"summary"</span><span class="token punctuation">:</span> <span class="token string">"Frank Abagnale Jr, master of deception"</span><span class="token punctuation">,</span> <span class="token string">"date"</span> <span class="token punctuation">:</span> <span class="token string">"2002"</span><span class="token punctuation">,</span> <span class="token string">"duration"</span><span class="token punctuation">:</span> <span class="token string">"135 minutes"</span><span class="token punctuation">,</span> <span class="token string">"rating"</span><span class="token punctuation">:</span> <span class="token string">"12"</span><span class="token punctuation">,</span> <span class="token string">"cover"</span> <span class="token punctuation">:</span> <span class="token string">"none"</span><span class="token punctuation">,</span> <span class="token string">"actors"</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Tom Hanks"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Leonardo Dicaprio"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Christopher Walken"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"genres"</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Action"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"name"</span> <span class="token punctuation">:</span> <span class="token string">"Thriller"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> |
Она содержит три записи о фильмах с вложенными данными об актерах и жанрах.
Я выбрал вложенную структуру данных вместо разделения узлов актеров и жанров на отдельные коллекции, так как это более практично при использовании AngularFire2 (мы обсудим причины этого позже).
Убедитесь, что сохранили JSON-файл как database.json (мы используем его, чтобы наполнить базу данных Firebase).
Вернитесь в консоль Firebase, выберите опцию Database из меню слева и во вкладке Data выберите опцию Import JSON:
Выберите файл database.json, который вы сохранили несколько моментов назад, и импортируйте его в базу данных:
Как было указано выше, мы могли бы создать базу данных вручную внутри консоли Firebase Database, но импорт заполненной JSON-структуры – это более быстрый и эффективный способ создания необходимых данных для проекта.
Как только база данных заполнена, она будет выглядеть следующим образом (Я позволил себе развернуть конечный узел в базе данных, чтобы показать ключи/значения, содержащиеся внутри):
Базы данных по существу представляют собой не что иное, как JSON-деревья в Firebase и их масштабировать гораздо проще, чем традиционные SQL-структуры. Тем не менее, это требует понимания таких методов, как денормализация, и я бы посоветовал любому разработчику, который еще не знаком с Firebase, прочитать этот документ, касающийся структурирования базы данных.
Когда база данных заполнена, остался один последний шаг, который касается конфигурации правил безопасности для доступа.
Во вкладке Rules панели Database сделайте следующие изменения:
Здесь мы просто прокомментируем правила по умолчанию, в дублированных правилах установите для ключей чтения и записи НЕ требовать аутентификацию.
Мы могли, конечно, оставить такие правила по умолчанию:
1 2 3 4 5 6 |
<span class="token punctuation">{</span> <span class="token string">"rules"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">".read"</span><span class="token punctuation">:</span> <span class="token string">"auth != null"</span><span class="token punctuation">,</span> <span class="token string">".write"</span><span class="token punctuation">:</span> <span class="token string">"auth != null"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
А затем использовать API аутентификации AngularFire2 для получения доступа к базе данных (после настройки метода аутентификации, например, через e-mail и пароль, в разделе Authentication аккаунта Firebase).
Для этого урока мы сделаем всё просто и отключим правила безопасности для доступа к базе данных (в настоящем проекта так делать нельзя по очевидным причина, если вы, конечно, не хотите давать неавторизованный доступ к вашим данным).
Теперь давайте исследуем AngularFire2.
AngularFire2
Благодаря использованию Ionic фреймворка Angular, мы можем использовать множество node пакетов в наших проектах.
AngularFire2 является одним из этих пакетов и предоставляет разработчикам возможность интегрировать Firebase в свои приложения со следующими функциями:
- Простой и удобный API
- Методы аутентификации для базы данных
- Связь в режиме реального времени
Последняя, но самая главная функция в AngularFire2 – обновление UI приложения в реальном времени, чтобы отражать любые изменения в данных Firebase.
Это, на самом деле, очень полезно, так как это означает, что нам не нужно внедрять логику, чтобы научить пользовательский интерфейс приложения обновлять себя и осуществлять эти изменения – AngularFire2 просто делает это за нас в фоновом режиме.
Всё это звучит отлично, но у пакета есть серьезные ограничения:
- Нельзя загружать изображения в хранилище Firebase
- Выполнение запросов в нескольких коллекциях (аналогично SQL-реляционной базе данных) невозможно
Всё это делает AngularFire2, мягко говоря, довольно ограниченной для применения в крупных Ionic-проектах, что печально, потому что пакет просто внедрить и он легко синхронизирует изменения UI с обновлениями данных Firebase.
Надеюсь, что разработчики AngularFire2 смогут устранить эти ограничения и обеспечат эти функции в будущих релизах, но пока мы просто будем работать с текстовыми данными в нашей базе.
Создание проекта
Со стороны сервера всё настроено, поэтому приступим к созданию проекта Ionic.
Откройте окно командной строки (т.е. терминал, если вы используете Mac OS X, или командную строку, если находитесь на платформе Windows), перейдите в нужный системный каталог и выполните следующую команду для создания проекта с именем moveez:
1 |
ionic start moveez blank |
Как только проект будет создан, внесите изменения в него:
1 |
cd moveez |
И установите следующее:
1 2 |
npm install -g typings npm install angularfire2 firebase --save |
Мы начинаем с установки необходимых определений типов, чтобы компилятор проекта мог работать с пакетами Firebase и AngularFire2 (которые потом и устанавливаются – в следующей же строке).
Наконец, мы завершаем конфигурацию проекта, создавая модальный компонент:
1 |
ionic g page modals |
Теперь создадим root-модуль для приложения Moveez.
Рутинг для Moveez
Как и со всеми вещами Ionic или Angular, мы должны сделать так, чтобы любые модули, необходимые для функционирования нашего приложения, были доступны root-модулю во время начальной загрузки/инициализации (а также, чтобы избежать этих полезных, но раздражающих сообщений об ошибках от транспилера при создании нашего приложения только для того, чтобы найти что-то, немного пошло не так в процессе).
Откройте файл moveez/src/app/app.module.ts и сделайте несколько поправок:
- Импортируйте AngularFireModule
- Добавьте объект конфигурации Firebase
Всё должно выглядеть следующим образом (не забудьте заменить API-KEY-IS-ENTERED-HERE, YOUR-PROJECT-NAME-HERE, YOUR-DATABASE-NAME-HERE, YOUR-STORAGE-BUCKET-NAME-HERE AND YOUR-MESSAGING-SENDER-ID-HERE настоящими значениями из конфигурации Add Firebase to your Web App, которые вы скопировали и сохранили ранее):
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 43 44 |
<span class="token keyword keyword-import">import</span> <span class="token punctuation">{</span> BrowserModule <span class="token punctuation">}</span> <span class="token keyword keyword-from">from</span> <span class="token string">'@angular/platform-browser'</span><span class="token punctuation">;</span> <span class="token keyword keyword-import">import</span> <span class="token punctuation">{</span> HttpModule <span class="token punctuation">}</span> <span class="token keyword keyword-from">from</span> <span class="token string">'@angular/http'</span><span class="token punctuation">;</span> <span class="token keyword keyword-import">import</span> <span class="token punctuation">{</span> ErrorHandler<span class="token punctuation">,</span> NgModule <span class="token punctuation">}</span> <span class="token keyword keyword-from">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span> <span class="token keyword keyword-import">import</span> <span class="token punctuation">{</span> IonicApp<span class="token punctuation">,</span> IonicErrorHandler<span class="token punctuation">,</span> IonicModule <span class="token punctuation">}</span> <span class="token keyword keyword-from">from</span> <span class="token string">'ionic-angular'</span><span class="token punctuation">;</span> <span class="token keyword keyword-import">import</span> <span class="token punctuation">{</span> SplashScreen <span class="token punctuation">}</span> <span class="token keyword keyword-from">from</span> <span class="token string">'@ionic-native/splash-screen'</span><span class="token punctuation">;</span> <span class="token keyword keyword-import">import</span> <span class="token punctuation">{</span> StatusBar <span class="token punctuation">}</span> <span class="token keyword keyword-from">from</span> <span class="token string">'@ionic-native/status-bar'</span><span class="token punctuation">;</span> <span class="token keyword keyword-import">import</span> <span class="token punctuation">{</span> MyApp <span class="token punctuation">}</span> <span class="token keyword keyword-from">from</span> <span class="token string">'./app.component'</span><span class="token punctuation">;</span> <span class="token keyword keyword-import">import</span> <span class="token punctuation">{</span> HomePage <span class="token punctuation">}</span> <span class="token keyword keyword-from">from</span> <span class="token string">'../pages/home/home'</span><span class="token punctuation">;</span> <span class="token keyword keyword-import">import</span> <span class="token punctuation">{</span> AngularFireModule <span class="token punctuation">}</span> <span class="token keyword keyword-from">from</span> <span class="token string">'angularfire2'</span><span class="token punctuation">;</span> <span class="token keyword keyword-export">export</span> <span class="token keyword keyword-const">const</span> firebaseConfig <span class="token operator">=</span> <span class="token punctuation">{</span> apiKey <span class="token punctuation">:</span> <span class="token string">'API-KEY-IS-ENTERED-HERE'</span><span class="token punctuation">,</span> authDomain <span class="token punctuation">:</span> <span class="token string">'https://console.firebase.google.com/project/YOUR-PROJECT-NAME-HERE'</span><span class="token punctuation">,</span> databaseURL <span class="token punctuation">:</span> <span class="token string">'https://YOUR-DATABASE-NAME-HERE.firebaseio.com/'</span><span class="token punctuation">,</span> storageBucket <span class="token punctuation">:</span> <span class="token string">'gs://YOUR-STORAGE-BUCKET-NAME-HERE.appspot.com'</span><span class="token punctuation">,</span> messagingSenderId <span class="token punctuation">:</span> <span class="token string">'YOUR-MESSAGING-SENDER-ID-HERE'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> @<span class="token function">NgModule</span><span class="token punctuation">(</span><span class="token punctuation">{</span> declarations<span class="token punctuation">:</span> <span class="token punctuation">[</span> MyApp<span class="token punctuation">,</span> HomePage <span class="token punctuation">]</span><span class="token punctuation">,</span> imports<span class="token punctuation">:</span> <span class="token punctuation">[</span> IonicModule<span class="token punctuation">.</span><span class="token function">forRoot</span><span class="token punctuation">(</span>MyApp<span class="token punctuation">)</span><span class="token punctuation">,</span> BrowserModule<span class="token punctuation">,</span> HttpModule<span class="token punctuation">,</span> AngularFireModule<span class="token punctuation">.</span><span class="token function">initializeApp</span><span class="token punctuation">(</span>firebaseConfig<span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> bootstrap<span class="token punctuation">:</span> <span class="token punctuation">[</span>IonicApp<span class="token punctuation">]</span><span class="token punctuation">,</span> entryComponents<span class="token punctuation">:</span> <span class="token punctuation">[</span> MyApp<span class="token punctuation">,</span> HomePage <span class="token punctuation">]</span><span class="token punctuation">,</span> providers<span class="token punctuation">:</span> <span class="token punctuation">[</span> StatusBar<span class="token punctuation">,</span> SplashScreen<span class="token punctuation">,</span> <span class="token punctuation">{</span>provide<span class="token punctuation">:</span> ErrorHandler<span class="token punctuation">,</span> useClass<span class="token punctuation">:</span> IonicErrorHandler<span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword keyword-export">export</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">AppModule</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> |
Итого
Во время этого урока мы познакомились с созданием базы данных Firebase, создали базовый каркас проекта Ionic, установили необходимые пакеты и определения типов и настроили наш root-модуль Ionic. Может показаться, что мы сделали немного, но мы настроили серверную сторону нашего проекта и создали основу мобильного приложения.
Продолжение во второй части!