Привет, я Андрей, работаю Flutter разработчиком в компании Финам.
В этой части мы сделаем рефакторинг проекта и подключим клиентское Flutter приложение к сервису Umka.
Рефакторинг проектa
Репозиторий для описания и сгенерированного кода проекта Umka
Выделим в отдельный проект описание сервиса Umka на IDL Progobuf и сгенерированные для сервиса файлы. Поместим код в репозиторий umka_proto на Github.
Репозиторий для сервиса Umka
Удалим из проекта Umka Service описание umka.proto и папку для сгенерированного базового Dart кода сервиса lib/generated
.
Репозиторий umka_service.
Фактически здесь у нас осталось только 2 файла:
Код для серверного приложения service.dart
Код для извлечения вопросов из импровизированной базы questions_db_driver.dart
Базовый код подключим в виде зависимости umka_proto
:
Теперь все готово для подключения к сервису мобильного Flutter приложения.
Мобильное Flutter приложение для работы с сервисом Umka
Целью даной серии не является описание процесса создания Flutter приложения, поэтому я дам краткий обзор как оно устроено и ссылку на исходный код.
Umka-Flutter это не полноценное мобильное приложение, а лишь прототип для демонстрации использования сервиса Umka, создание которого мы рассмотрели в предыдущих 3х частях цикла, и который также является демонстрационным прототипом сервиса на основе технологии gRPC.
Подробнее мы рассмотрим код отвечающий за взаимодействие с gRPC сервисом.
Для управления состоянием я выбрал Bloc, конкретнее Cubit, как один из наиболее популярных и не очень "вербозных" подходов.
На главном экране расположено 3 вкладки:
Quiz, отправка ответа на случайный вопрос.
Tutorial, ответы на список вопросов, полученных от сервиса, с индикацией правильного ответа.
Exam, импровизированное прохождение экзамена.
Структура проекта мобильного приложения
Подключение нашей библиотеки umka_proto
делается точно также как и для сервиса:
Файловая структура проекта выглядит так:
У нас есть home_screen.dart
в папке lib/ui/home
где реализована навигация по трём вкладкам, а также 3 директории для "фич": lib/ui/quiz
, lib/ui/tutorial
и lib/ui/exam
, в каждой из которых присутствуют .dart
файлы с кодом для:
хранения состояния (*state.dart)
бизнес логики и изменения состояния (*cubit.dart)
отображения пользовательского интерфейса (*view.dart)
Удалённые вызовы сервиса Umka описаны в файле lib/services/umka_service.dart
. Код вызовов практически полностью идентичен тому, который мы рассматривали в предыдущих трёх частях серии для терминального клиента class UmkaTerminalClient
.
Остальные файлы в проекте являются стандартными для Flutter проекта или вспомогательными.
Код мобильного приложения Umka
ссылка на репозиторий с исходным кодом проекта
Логика работы
Работа с удаленными вызовами сервиса осуществляется исключительно в файлах *cubit.dart
:
Делаем запрос нужной информации на сервисе или отправляем сервису данные.
Получаем от сервиса ответ.
В зависимости от полученного ответа меняем состояние
class *State
для соответствующей "фичи" нужным образом, отправляя новое состояние методамиemit(newState)
расположенными вclass *Cubit
.
Вкладка Quiz
Демонстрация работы
Вводим имя.
Нажимаем кнопку "Get Random Question".
Отображается вопрос, на который мы вводим ответ.
Отправляем ответ на сервис.
Сервис оценивает ответ и присылает результат.
И так "по кругу" сколько угодно раз.
За логику работы отвечает класс QuizCubit
, находящийся в файле lib/ui/quiz/quiz_cubit.dart
.
По заполнению поля с именем появляется кнопка "Get Random Question" и после её нажатия срабатывает метод getRandomQuestion()
, в котором происходит удаленный вызов на сервис:
final question = await umkaService.getRandomQuestion(student);
.
Вопрос запоминается в QuizState
и отображается для студента. Он заполняет поле с ответом и отправляет его сервису:
final evaluation = await umkaService.sendAnswer(answer);
.
В ответе evaluation
приходит результат правильным был ответ или нет, который и отображается студенту.
Вкладка Tutorial
Работает это так:
Вводим имя и нажимаем кнопку "Start".
С сервиса начинают потоком поступать вопросы, примерно каждые 2 секунды.
Вводим ответ на каждый вопрос.
"Чекаем" ответы, и сразу видим результат верно или нет.
Исправляем ошибочные ответы.
Работа с сервисом происходит в классе TutorialCubit
:
Метод takeTutorial()
срабатывает по нажатии кнопки "Start". На строке №20 мы "подписываемся" на поток вопросов от сервиса и обрабатываем их по одному. С сервиса "прилетают" уже отвеченные вопросы, поэтому после проставления галочки, мы немедленно видим результат.
Вкладка Exam
"Экзамен" проводится следующим образом:
"Студент" вводит своё имя и нажимает кнопку готовности к экзамену.
Сервис присылает все экзаменационные вопросы и первый из них отображается на экране.
После ввода ответа экзаменуемый кнопкой "Send..." отправляет ответ в поток соединения с сервисом.
Появляется следующий вопрос ... .
После отправки ответа на последний вопрос сервис присылает итоговую "оценку".
Взаимодействие с сервисом происходит в классе ExamCubit:
Нажатие кнопки "Send ..." запускает метод takeExam(String name)
. Вопросы запрашиваются на сервисе и сохраняются в объекте exam
:
final exam = await umkaService.getExam(state.student);
Создается соединение с сервисом, на который передается стрим для для отправки ответов:
final evaluation = await umkaService.takeExam(state.student.name, answersStream!.stream);
После получения всех ответов, сервис вернет "оценку", которая помещается в объект evaluation
.
Метод sendAnswer(String enteredAnswer)
просто добавляет ответы в стрим, переданный сервису.
Запускаем сервис и приложение на локальном компьютере
Я приведу для примера набор команд, с помощью которых можно склонировать исходники и запустить приложение и сервис, чтобы можно было всё "пощупать руками", "погулять" по коду и посмотреть логи.
Чтобы всё сработало на компьютере должны быть установлены Git и Dart и Flutter. Также запустите симулятор или эмулятор мобильного устройства или подсоедините реальное. Командой flutter devices
убедитесь, что мобильное устройство видно и находится первым в списке доступных.
Открываем терминал, создаем директорию
umka_demo
и переходим в нее:
mkdir umka_demo & cd umka_demo
Клонируем исходники сервиса:
git clone https://github.com/Umka-org/umka_service.git
Клонируем исходники мобильного приложения:
git clone https://github.com/Umka-org/umka_flutter_app.git
Переходим в папку с сервисом, "подтягиваем" зависимости и запускаем сервис:
cd umka_service && pub get && dart lib/service.dart
Открываем рядом второй терминал, переходим в папку с мобильным приложением, добавляем в проект нужные библиотеки и запускаем мобильное приложение:
cd umka_demo/umka_flutter_app && flutter pub get && flutter run
Если все сработало, наслаждаемся, если же что-то пошло не так, сильно не злимся, а устраняем проблемы. Я проверил работоспособность приведённых команд на маке и Ubuntu.
На этом данная серия из четырех статей завершена. Надеюсь было полезно. Спасибо всем, кто дочитал до конца и поддерживал меня.
До встречи!
bus_pro
flutter рулит!
Наверное ещё никогда порог входа в новые технологии не был столь мал. И замечательно, что сразу на гребне волны с последними фишками такими, как gRPC и много другого, да ещё под любые платформы.
Автору большое спасибо, что провел нас от начала до успешного финала с запуском приложения.
Andrey_chik Автор
Малый порог входа, к сожалению, имеет и "оборотную сторону медали".
artchalet
Если не трудно, уточните пожалуйста про "оборотную сторону медали" ?
Andrey_chik Автор
Я про фразу "Наверное ещё никогда порог входа в новые технологии не был столь мал." понял так, что имеется ввиду не материальный порог, вроде "Чтобы делать iOs приложения тебе нужен Мак и платная подписка на девелоперский аккаунт Apple", а то, что требуется относительно невысокий уровень квалификации в разработке и/или временные затраты, чтобы научиться делать Flutter приложения, что в основном хорошо.