Создайте приложение для Android с помощью Firebase и Jetpack Compose.

1. Введение

Последнее обновление: 16.11.2022

Разработка Android-приложения с использованием Firebase и Jetpack Compose.

В этом практическом занятии вы создадите Android-приложение под названием Make It So. Пользовательский интерфейс этого приложения полностью построен с помощью Jetpack Compose , современного инструментария Android для создания нативных пользовательских интерфейсов — он интуитивно понятен и требует меньше кода, чем написание XML-файлов и их привязка к Activity, Fragment или View.

Первый шаг к пониманию того, насколько хорошо Firebase и Jetpack Compose работают вместе, — это понимание современной архитектуры Android. Хорошая архитектура делает систему простой для понимания, разработки и сопровождения, поскольку она четко показывает, как компоненты организованы и взаимодействуют друг с другом. В мире Android рекомендуемая архитектура называется Model - View - ViewModel . Model представляет собой слой, который обращается к данным в приложении. View — это слой пользовательского интерфейса, и он не должен знать ничего о бизнес-логике. А ViewModel — это место, где применяется бизнес-логика, которая иногда требует, чтобы ViewModel обращался к слою Model .

Мы настоятельно рекомендуем прочитать эту статью , чтобы понять, как применяется модель - представление - ViewModel в Android-приложении, созданном с помощью Jetpack Compose, поскольку это упростит понимание кода и выполнение последующих шагов.

Что вы построите

Make It So — это простое приложение для составления списков дел, позволяющее пользователю добавлять и редактировать задачи, устанавливать флажки, приоритеты и сроки выполнения, а также отмечать задачи как выполненные. На изображениях ниже показаны две основные страницы этого приложения: страница создания задачи и главная страница со списком созданных задач.

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

Вы добавите некоторые функции, которых нет в этом приложении:

  • Аутентификация пользователей с помощью электронной почты и пароля.
  • Добавьте обработчик событий к коллекции Firestore и настройте пользовательский интерфейс на реагирование на изменения.
  • Добавьте пользовательские трассировки для мониторинга производительности конкретного кода в приложении.
  • Создайте переключатель функций с помощью удаленной конфигурации и используйте поэтапное развертывание для его запуска.

Что вы узнаете

  • Как использовать аутентификацию Firebase, мониторинг производительности, удаленную конфигурацию и Cloud Firestore в современном Android-приложении
  • Как интегрировать API Firebase в архитектуру MVVM
  • Как отобразить изменения, внесенные с помощью API Firebase, в пользовательском интерфейсе Compose.

Что вам понадобится

2. Загрузите демонстрационное приложение и настройте Firebase.

Получите код демонстрационного приложения.

Клонируйте репозиторий GitHub из командной строки:

git clone https://github.com/FirebaseExtended/make-it-so-android.git

Создайте проект Firebase.

  1. Войдите в консоль Firebase, используя свою учетную запись Google.
  2. Нажмите кнопку, чтобы создать новый проект, а затем введите название проекта (например, Compose Firebase codelab ).
  3. Нажмите «Продолжить» .
  4. Если появится запрос, ознакомьтесь с условиями использования Firebase и примите их, после чего нажмите «Продолжить» .
  5. (Необязательно) Включите помощь ИИ в консоли Firebase (в Firebase она называется "Gemini").
  6. Для выполнения этого практического задания вам потребуется Google Analytics для использования расширенных параметров таргетинга с помощью функции удаленной настройки, поэтому оставьте переключатель для параметра Google Analytics включенным . Следуйте инструкциям на экране, чтобы настроить Google Analytics.
  7. Нажмите «Создать проект» , дождитесь завершения подготовки проекта, а затем нажмите «Продолжить» .

Добавьте Android-приложение в свой проект Firebase.

В вашем проекте Firebase вы можете зарегистрировать различные приложения: для Android, iOS, веб-приложений, Flutter и Unity.

Выберите вариант для Android, как показано здесь:

Обзор проекта Firebase

Затем выполните следующие шаги:

  1. Введите com.example.makeitso в качестве имени пакета и, при желании, укажите псевдоним. Для этого практического задания добавлять сертификат подписи отладки не требуется.
  2. Нажмите «Далее» , чтобы зарегистрировать приложение и получить доступ к файлу конфигурации Firebase.
  3. Нажмите «Скачать google-services.json» , чтобы загрузить файл конфигурации и сохранить его в каталоге make-it-so-android/app .
  4. Нажмите «Далее» . Поскольку SDK Firebase уже включены в файл build.gradle в примере проекта, нажмите «Далее» , чтобы перейти к следующим шагам .
  5. Нажмите «Продолжить» в консоли , чтобы завершить.

Для корректной работы приложения Make it So необходимо выполнить два действия в консоли, прежде чем переходить к коду: включить поставщиков аутентификации и создать базу данных Firestore.

Настройка аутентификации

Для начала давайте включим аутентификацию, чтобы пользователи могли входить в приложение:

  1. В меню «Создание» выберите «Аутентификация» , а затем нажмите «Начать» .
  2. В карточке «Способ входа» выберите «Электронная почта/Пароль» и включите эту опцию.
  3. Далее нажмите «Добавить нового поставщика услуг» , выберите и включите анонимный режим .

Настройка Cloud Firestore

Далее настройте Firestore. Вы будете использовать Firestore для хранения задач авторизованного пользователя. Каждый пользователь получит свой собственный документ в коллекции базы данных.

  1. В левой панели консоли Firebase разверните раздел «Сборка» , а затем выберите базу данных Firestore .
  2. Нажмите «Создать базу данных» .
  3. Оставьте значение параметра " Идентификатор базы данных" равным (default) .
  4. Выберите местоположение для вашей базы данных, затем нажмите «Далее» .
    Для создания настоящего приложения вам следует выбрать местоположение, расположенное недалеко от ваших пользователей.
  5. Нажмите «Пуск» в тестовом режиме . Ознакомьтесь с отказом от ответственности в отношении правил безопасности.
    На следующих шагах этого раздела вы добавите правила безопасности для защиты ваших данных. Не распространяйте и не предоставляйте доступ к приложению публично, не добавив правила безопасности для вашей базы данных.
  6. Нажмите «Создать» .

Давайте уделим немного времени созданию надежных правил безопасности для базы данных Firestore.

  1. Откройте панель управления Firestore и перейдите на вкладку «Правила» .
  2. Обновите правила безопасности следующим образом:
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /tasks/{document} {
      allow create: if request.auth != null;
      allow read, update, delete: if request.auth != null
        && resource.data.userId == request.auth.uid
        && request.data.userId == resource.data.userId;
    }
  }
}

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

Запустите приложение

Теперь вы готовы запустить приложение! Откройте папку make-it-so-android/start в Android Studio и запустите приложение (это можно сделать с помощью эмулятора Android или реального устройства Android).

3. Аутентификация Firebase

Какую функцию вы собираетесь добавить?

В текущей версии демонстрационного приложения Make It So пользователь может начать использовать приложение без предварительного входа в систему. Для этого используется анонимная аутентификация. Однако анонимные учетные записи не позволяют пользователю получать доступ к своим данным на других устройствах или даже в будущих сессиях. Хотя анонимная аутентификация полезна для «теплого» знакомства с приложением, всегда следует предоставлять пользователям возможность перейти на другой способ входа. С учетом этого, в этом практическом задании вы добавите в приложение Make It So аутентификацию по электронной почте и паролю.

Пора программировать!

Как только пользователь создаст учетную запись, введя адрес электронной почты и пароль, вам необходимо запросить у API аутентификации Firebase учетные данные электронной почты, а затем связать новые учетные данные с анонимной учетной записью. Откройте файл AccountServiceImpl.kt в Android Studio и обновите функцию linkAccount следующим образом:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String) {
    val credential = EmailAuthProvider.getCredential(email, password)
    auth.currentUser!!.linkWithCredential(credential).await()
}

Теперь откройте файл SignUpViewModel.kt и вызовите функцию linkAccount сервиса внутри блока launchCatching функции onSignUpClick :

screens/sign_up/SignUpViewModel.kt

launchCatching {
    accountService.linkAccount(email, password)
    openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}

Сначала выполняется попытка аутентификации, и если вызов проходит успешно, происходит переход к следующему экрану (экрану SettingsScreen ). Поскольку эти вызовы выполняются внутри блока launchCatching , если на первой строке возникнет ошибка, исключение будет перехвачено и обработано, и вторая строка вообще не будет достигнута.

Как только снова откроется SettingsScreen , необходимо убедиться, что параметры «Войти» и «Создать учетную запись» исчезли, поскольку пользователь уже аутентифицирован. Для этого настроим SettingsViewModel на отслеживание статуса текущего пользователя (доступно в AccountService.kt ), чтобы проверить, является ли учетная запись анонимной или нет. Для этого обновите uiState в SettingsViewModel.kt следующим образом:

screens/settings/SettingsViewModel.kt

val uiState = accountService.currentUser.map {
    SettingsUiState(it.isAnonymous)
}

Последнее, что вам нужно сделать, это обновить uiState в SettingsScreen.kt , чтобы он собирал состояния, передаваемые SettingsViewModel :

screens/settings/SettingsScreen.kt

val uiState by viewModel.uiState.collectAsState(
    initial = SettingsUiState(false)
)

Теперь при каждом изменении пользователя SettingsScreen будет перестраиваться, отображая параметры в соответствии с новым состоянием аутентификации пользователя.

Пора тестировать!

Запустите Make it So и перейдите в настройки, нажав на значок шестеренки в правом верхнем углу экрана. Там нажмите на опцию «Создать учетную запись»:

Экран настроек Make it SoЭкран регистрации Make it So

Введите действительный адрес электронной почты и надежный пароль для создания учетной записи. После этого вы должны перейти на страницу настроек, где увидите две новые опции: выход из учетной записи и ее удаление. Проверить созданную учетную запись можно на панели управления аутентификацией в консоли Firebase, перейдя на вкладку «Пользователи».

4. Cloud Firestore

Какую функцию вы собираетесь добавить?

Для Cloud Firestore вам потребуется добавить слушатель в коллекцию Firestore, которая хранит документы, представляющие задачи, отображаемые в Make it So. После добавления этого слушателя вы будете получать все обновления, внесенные в эту коллекцию.

Пора программировать!

Обновите Flow доступный в StorageServiceImpl.kt , следующим образом:

model/service/impl/StorageServiceImpl.kt

override val tasks: Flow<List<Task>>
    get() =
      auth.currentUser.flatMapLatest { user ->
        firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
      }

Этот код добавляет обработчик событий к коллекции задач на основе user.id Каждая задача представлена ​​документом в коллекции с именем tasks , и каждая из них имеет поле с именем userId . Обратите внимание, что новый Flow будет сгенерирован, если статус currentUser изменится (например, при выходе из системы).

Теперь вам нужно настроить Flow в файле TasksViewModel.kt так, чтобы он соответствовал потоку в сервисе:

screens/tasks/TasksViewModel.kt

val tasks = storageService.tasks

И последнее, что нужно сделать, это заставить composable function в файле TasksScreens.kt , которая представляет пользовательский интерфейс, отслеживать этот поток и собирать его как состояние. Каждый раз, когда состояние изменяется, компонуемая функция будет автоматически перестраиваться и отображать пользователю самое последнее состояние. Добавьте это в TasksScreen composable function :

screens/tasks/TasksScreen.kt

val tasks = viewModel
    .tasks
    .collectAsStateWithLifecycle(emptyList())

Как только компонуемая функция получит доступ к этим состояниям, вы можете обновить LazyColumn (структуру, используемую для отображения списка на экране) следующим образом:

screens/tasks/TasksScreen.kt

LazyColumn {
    items(tasks.value, key = { it.id }) { taskItem ->
        TaskItem( [...] )
    }
}

Пора тестировать!

Чтобы проверить работоспособность, добавьте новую задачу с помощью приложения (нажав кнопку «Добавить» в правом нижнем углу экрана). После создания задачи она должна появиться в коллекции Firestore в консоли Firestore. Если вы войдете в Make it So на других устройствах с той же учетной записью, вы сможете редактировать свои задачи и наблюдать за их обновлением на всех устройствах в режиме реального времени.

5. Мониторинг производительности

Какую функцию вы собираетесь добавить?

Производительность — очень важный параметр, на который следует обращать внимание, поскольку пользователи с большой вероятностью откажутся от использования вашего приложения, если его производительность низкая и выполнение простых задач занимает слишком много времени. Именно поэтому иногда полезно собирать метрики о конкретном пути пользователя в вашем приложении. И чтобы помочь вам в этом, Firebase Performance Monitoring предлагает пользовательские трассировки . Следуйте приведенным ниже шагам, чтобы добавить пользовательские трассировки и измерить производительность в различных фрагментах кода в Make it So.

Пора программировать!

Если вы откроете файл Performance.kt , вы увидите встроенную функцию с именем trace. Эта функция вызывает API мониторинга производительности для создания пользовательской трассировки, передавая имя трассировки в качестве параметра. Другой параметр, который вы увидите, — это блок кода, который вы хотите отслеживать. По умолчанию для каждой трассировки собирается метрика времени, необходимого для полного выполнения:

model/service/Performance.kt

inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)

Вы можете выбрать, какие части кода, по вашему мнению, важно измерить, и добавить к ним пользовательские трассировки. Вот пример добавления пользовательской трассировки к функции linkAccount , которую вы видели ранее (в AccountServiceImpl.kt ) в этом практическом задании:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String): Unit =
  trace(LINK_ACCOUNT_TRACE) {
      val credential = EmailAuthProvider.getCredential(email, password)
      auth.currentUser!!.linkWithCredential(credential).await()
  }

Теперь ваша очередь! Добавьте несколько пользовательских трассировок в приложение Make it So и перейдите к следующему разделу, чтобы проверить, работает ли оно должным образом.

Пора тестировать!

После добавления пользовательских трассировок запустите приложение и убедитесь, что несколько раз использовали функции, которые хотите измерить. Затем перейдите в консоль Firebase и откройте панель мониторинга производительности . В нижней части экрана вы найдете три вкладки: «Сетевые запросы» , «Пользовательские трассировки» и «Отображение экрана» .

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

6. Удалённая настройка

Какую функцию вы собираетесь добавить?

У функции Remote Config множество вариантов применения: от удалённого изменения внешнего вида приложения до настройки различного поведения для разных сегментов пользователей. В этом практическом занятии вы используете Remote Config для создания переключателя функций, который будет отображать или скрывать новую функцию редактирования задач в приложении Make it So.

Пора программировать!

Первое, что вам нужно сделать, это создать конфигурацию в консоли Firebase. Для этого перейдите на панель управления Remote Config и нажмите кнопку «Добавить параметр» . Заполните поля в соответствии с изображением ниже:

Диалоговое окно «Создать параметр» в разделе «Удалённая настройка»

После заполнения всех полей нажмите кнопку «Сохранить» , а затем «Опубликовать» . Теперь, когда параметр создан и доступен в вашем коде, вам необходимо добавить в приложение код, который будет получать новые значения. Откройте файл ConfigurationServiceImpl.kt и обновите реализацию следующих двух функций:

model/service/impl/ConfigurationServiceImpl.kt

override suspend fun fetchConfiguration(): Boolean {
  return remoteConfig.fetchAndActivate().await()
}

override val isShowTaskEditButtonConfig: Boolean
  get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()

Первая функция получает значения с сервера и вызывается сразу после запуска приложения, в файле SplashViewModel.kt . Это лучший способ гарантировать, что самые актуальные значения будут доступны на всех экранах с самого начала. Изменение пользовательского интерфейса или поведения приложения позже, когда пользователь занят другими делами, — это плохой пользовательский опыт!

Вторая функция возвращает логическое значение, опубликованное для параметра, который вы только что создали в консоли. Вам потребуется получить эту информацию в TasksViewModel.kt , добавив следующее в функцию loadTaskOptions :

screens/tasks/TasksViewModel.kt

fun loadTaskOptions() {
  val hasEditOption = configurationService.isShowTaskEditButtonConfig
  options.value = TaskActionOption.getOptions(hasEditOption)
}

Вы получаете значение из первой строки и используете его для загрузки пунктов меню для элементов задачи во второй строке. Если значение равно false , это означает, что меню не будет содержать опцию редактирования. Теперь, когда у вас есть список опций, вам нужно правильно отобразить их в пользовательском интерфейсе. Поскольку вы создаете приложение с помощью Jetpack Compose, вам нужно найти composable function , которая определяет, как должен выглядеть пользовательский интерфейс TasksScreen . Поэтому откройте файл TasksScreen.kt и обновите LazyColum , чтобы он указывал на параметры, доступные в TasksViewModel.kt :

screens/tasks/TasksScreen.kt

val options by viewModel.options

LazyColumn {
  items(tasks.value, key = { it.id }) { taskItem ->
    TaskItem(
      options = options,
      [...]
    )
  }
}

TaskItem — это ещё одна composable function , которая определяет внешний вид пользовательского интерфейса отдельной задачи. Каждая задача имеет меню с опциями, которое отображается, когда пользователь щёлкает по значку с тремя точками в конце меню.

Пора тестировать!

Теперь вы готовы запустить приложение! Убедитесь, что значение, опубликованное вами через консоль Firebase, соответствует поведению приложения:

  • Если это false , при нажатии на значок с тремя точками вы должны увидеть только два варианта;
  • Если это true , то при нажатии на значок с тремя точками вы должны увидеть три варианта;

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

7. Поздравляем!

Поздравляем, вы успешно создали Android-приложение с помощью Firebase и Jetpack Compose!

Вы добавили аутентификацию Firebase, мониторинг производительности, удаленную конфигурацию и Cloud Firestore в Android-приложение, полностью созданное с использованием Jetpack Compose для пользовательского интерфейса, и адаптировали его к рекомендуемой архитектуре MVVM!

Дополнительная информация

Справочная документация