Журнал / польза

Что учесть при разработке мобильного Flutter-приложения: чек-лист

Ваш проект — это не только код. На старте разработки приложения здорово обратить внимание и на другие, не менее важные аспекты, которые сделают проект качественнее и удобнее. Собрали чек-лист вместе с Сергеем Кольцовым, руководителем группы Flutter-разработки в Яндексе.

Flutter — кроссплатформенный UI-фреймворк для разработки мобильных приложений, написанный на языке программирования Dart. Его главное преимущество — пишешь код один раз, а затем компилируешь для Android, iOS, десктопа и других платформ. Экономит уйму времени и ресурсов.

Если есть небольшой опыт программирования, начать писать на Flutter легко:

1. Зайдите на docs.flutter.dev.

2. Установите окружение и инструменты по инструкции.

3. Выберите удобную среду разработки — чаще всего Android Studio или VS Code.

4. Создайте проект — и вот базовое приложение готово.

Разобраться в нюансах написания кода на Flutter поможет архив лекций открытого лектория от Летних школ Академии Яндекса, который прошёл в 2022 году. После просмотра ваше приложение обзаведётся новыми фичами, работой с сервером, хранилищем, архитектурой.

Если совсем незнакомы с технологией, советую прочесть статью Ильи Вирника «Зачем учиться разработке на Flutter» и посмотреть мою вводную лекцию открытого лектория в Школе мобильной разработки Академии Яндекса.

Сергей Кольцов, руководитель группы Flutter-разработки в Яндексе

✅ Качество кода

Важно, чтобы код было легко читать, сопровождать, поддерживать и изменять. Есть набор инструментов, которые позволяют быстро и эффективно повысить качество кода:

Dart format автоматически форматирует код по рекомендациям стиля. Соблюдать их, особенно в команде, необходимо, иначе разработка превратится в бесконечные споры о правильных переносах и языковых конструкциях. Для использования установите Flutter и выполните команду dart format.

Линтер автоматически анализирует код, помогает найти нарушения стиля и логические ошибки. Лучше увидеть пустое тело в условной конструкции в момент написания кода, чем на тестировании. В каждый Flutter-проект линтер подключён по умолчанию, проверку выполняют командой flutter analyze. Детальная настройка правил — в файле analysis_options.yaml.

Dart Language Tour и Effective Dart — набор практик и рекомендаций, как писать Dart-код. Обязательно прочитайте правила сами и покажите коллегам: это поможет улучшить код и увидеть потенциальные ошибки на код-ревью.

✅ Сборка

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

1. Подписи и сертификаты. Их настройка на Android и IOS занимает время, поэтому не стоит откладывать это на момент перед релизом. Хорошо, что её делают только один раз и в дальнейшем минимально поддерживают.

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

✅ Окружение

Важно на старте подумать о подготовке окружения Flutter-проекта, чтобы сократить время на рутинные операции по настройке проекта для разработчиков.

Подготовьте init-скрипт в репозитории для настройки проекта. Это автоматизирует рутинные операции: инициализацию гитхуков, установку внешних зависимостей или конфигурацию особых параметров среды разработки. Например, вы можете подготовить гитхук, который будет срабатывать каждый раз, когда вы пушите код на сервер, а в init-скрипт добавить код, который поменяет стандартный путь до гитхуков на директорию с вашими:

# Ваши гитхуки должны лежать в директории .githooks
git config --local core.hooksPath .githooks/
chmod +x .githooks/pre-push

Настройте Flutter Version Manager (FVM), который управляет установленными версиями Flutter и легко переключается между ними. Если вы работаете над разными Flutter-проектами, то потенциально каждый из них может использовать другие версии Flutter, часто несовместимые между собой. В такой ситуации в каждом проекте настраивают FVM и полностью изолируют окружение проектов друг от друга.

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

Сделать скрипт кодогенерации. В базовом виде команда для кодогенерации выглядит так: flutter pub run build_runner build.

Работать с секретами. Это значения проекта, которые нельзя хранить в репозитории: API-ключи и токены внешних сервисов, релизные подписи и сертификаты, ключи от них. Для работы локально секреты хранят в файлах, которые игнорируются в репозитории в .gitignore. Так секреты не попадают в репозиторий и недоступны публично. 

✅ CI/CD

CI (Continuous Integration) — процесс, в котором новый код автоматически собирается и тестируется. Это позволяет разработчикам обнаружить ошибки и баги раньше, чем их найдут на ручном тестировании.

CD (Continuous Deployment) — процесс, где приложение автоматически распространяется на пользователей после успешной сборки и тестирования.

Настройка CI/CD помогает автоматизировать рутинные операции проверок, тестов и сборок. Также CI/CD минимизирует влияние человеческого фактора: всю работу выполняют прописанные алгоритмы. Большинство систем CI/CD поддерживают Flutter. Для старта можно попробовать:

Github Actions

Gitlab CI/CD

Codemagic

Например, чтобы проверить и собрать релизную Android-сборку и показать её тестировщикам, нужно:

1. Проверить, что код корректно отформатирован с помощью форматтера.
2. Проверить, что в коде нет ошибок, найденных линтером.
3. Выполнить кодогенерацию или проверить, что она актуальна после изменений.
4. Проверить, что успешно проходят все автотесты.
5. Выполнить команду сборки flutter build apk --release.
6. Взять получившийся apk-файл из директории build/app/outputs/flutter-apk и прислать его тестировщику.

Каждый из этих шагов занимает от нескольких секунд до десятков минут. В iOS-сборке таких шагов больше, а работа с секретами в разы сложнее и кропотливее. Поэтому лучше выделить один раз время на настройку CI/CD — и дальше всю работу будет делать машина, пока вы попиваете чай.

Сергей Кольцов, руководитель группы Flutter-разработки в Яндексе

✅ Логирование

Позволяет разработчикам отслеживать исполнение программы, идентифицировать и отлаживать ошибки и централизованно настраивать отображение и вывод логов. Логи могут стать хорошей альтернативой комментариям, объясняя происходящее в вашем коде. Базовая информация о логировании во Flutter есть в документации. Кроме того, вот хорошие практики.

Избегайте использования встроенной функции print. Она полезна для быстрой отладки, но print не позволяет настроить уровни логирования, тегировать сообщения, перенаправлять вывод в файл или на сервер. Поэтому лучше использовать специализированные библиотеки логирования: logger, logging или другие.

Настраивайте уровни отображения логов. Это способ фильтрации сообщений по уровню. Обычно существует несколько уровней: например, debug, info, warning, error или их вариации. Их настройка позволяет сфокусироваться на определённых типах сообщений, например на ошибках, и игнорировать остальные.

Не пишите в логи персональные данные пользователей в production-сборках. Это не только неэтично, но и нарушает законы о защите персональных данных.

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

Пример создания логгера с помощью пакета logging и его использования:

✅ Обработка ошибок

Заранее подумайте о двух ситуациях.

Ошибка ожидаема, и вы знаете, как её обрабатывать. Например, ошибка сервера, когда нужно повторить запрос. Или проблема получения данных из плагина — тогда нужно показать экран с ошибкой. Такие ошибки обрабатывают через try-catch: явно указывают тип ошибки и описывают поведение, в случае их возникновения.

Ошибка не ожидаема, и вы не знаете, как вести себя в коде, если она случилась. Их нельзя «замалчивать», делая try-catch и оставляя catch-блок пустым. Так вы усложните себе жизнь: ни в логах, ни в аналитике информации не будет. Их правильнее оставить необработанными (unhandled или uncaught), не делая try-catch, и дать фреймворку поймать их для централизованной обработки.

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

✅ Интернационализация

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

Во Flutter-приложении интернационализацию реализуют несколькими способами:

1. С помощью пакета flutter_localizations, который поставляется вместе с Flutter SDK.

2. Более расширенный вариант — с помощью пакета intl.

3. Через сторонние библиотеки.

✅ Тема и дизайн

Выделяют два способа управления темой во Flutter-приложении, причём они не взаимоисключающие. Для разных ситуаций подходят разные способы:

Централизованная тема для всего приложения позволяет управлять цветами, шрифтами и другими стилевыми элементами во всём приложении из одного места. Чтобы её использовать, нужно создать экземпляр класса ThemeData и задать параметры: цвета, шрифты и размеры для стандартных виджетов. Затем экземпляр вашей ThemeData вы передаёте в MaterialApp в аргумент theme — с этого момента все виджеты внутри MaterialApp будут использовать указанную тему.

Отдельные UI-компоненты. Вы можете создать отдельные универсальные виджеты (кнопки, поля для ввода, блоки с данными) с помощью Stateless- и Stateful-виджетов. Внутри них — описать стилистические характеристики и конкретизировать формат конфигурации компонента. Например, ограничить набор параметров или добавить собственные. Каждый виджет станет единой точкой изменения внешнего вида. Остальное приложение будет пользоваться им, не вдаваясь в детали реализации.

✅ Иконка

Для подготовки иконки есть несколько простых вариантов:

— Библиотека flutter_launcher_icons.

Встроенный генератор в Android Studio.

— Онлайн-генераторы.

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