Skip to main content
EngineeringProduct Building

Flutter в продакшене: Что мы узнали после выпуска 3 кроссплатформенных приложений

Mortgy
4 min read

Flutter — наш основной выбор для кроссплатформенных приложений. За прошлый год мы запустили три production Flutter приложения — финтех-приложение, платформу для онлайн-образования и инструмент для полевого обслуживания. Каждое из них научило нас чему-то новому о том, что Flutter делает хорошо, и где нужно быть осторожным. Вот настоящие уроки, а не маркетинговая речь.

Управление состоянием: мы остановились на Riverpod

После того как мы попробовали Provider, BLoC и Riverpod в разных проектах, мы стандартизировали все новые Flutter работы на Riverpod. Причина проста: он обрабатывает внедрение зависимостей и управление состоянием в единой паттерне, он безопасен на этапе компиляции (без ошибок времени выполнения из-за отсутствующих провайдеров) и работает идентично в тестах.

BLoC мощный, но чрезмерно формален для большинства приложений. Паттерн событие-состояние добавляет boilerplate, который замедляет разработку без пропорциональных преимуществ для типичных CRUD и приложений, управляемых API. Мы используем BLoC для сложных stateful функций, таких как редактирование в реальном времени в сотрудничестве, где явный поток событий действительно полезен.

Наша архитектура Riverpod следует трёхуровневому паттерну: UI виджеты зависят от контроллеров (StateNotifier или AsyncNotifier), контроллеры зависят от репозиториев, и репозитории зависят от источников данных (API клиенты, локальное хранилище). Каждый уровень независимо тестируется и граф зависимостей явный.

Производительность: правило 90%

Flutter даёт вам 60fps из коробки для 90% экранов. Остальные 10% — длинные прокручиваемые списки, сложные анимации наложенные на прямые трансляции данных и экраны со множеством одновременных сетевых изображений — требуют целенаправленной оптимизации. Наиболее эффективные оптимизации, которые мы нашли:

Используйте const конструкторы везде, где это возможно. Эта единственная практика предотвращает ненужные перестройки виджетов и является самым лёгким выигрышем производительности во Flutter. Мы применяем её через lint правила. Используйте ListView.builder вместо ListView для любого списка длиннее 20 элементов — он лениво создаёт только видимые элементы. Кэшируйте сетевые изображения с cached_network_image и установите соответствующие лимиты памяти. Для сложных анимаций используйте RepaintBoundary для изоляции дорогостоящих операций рисования.

Оверлей производительности Flutter DevTools — ваш лучший помощник. Мы запускаем его на каждом экране во время разработки и отмечаем любой кадр, который занимает более 16 мс. Большинство проблем с производительностью возникают из-за thrashing-а макета (глубоко вложенные виджеты, которые вызывают несколько проходов макета) или ненужных перестроений (провайдеры, которые уведомляют слушателей слишком широко).

Каналы платформы: связь с нативным кодом

Каждому приложению Flutter в конечном итоге нужен код для конкретной платформы. Для нашего финтех-приложения это была биометрическая аутентификация и защищённое хранилище. Для нашего приложения для образования это была обработка push-уведомлений с пользовательскими полезными нагрузками. Для нашего приложения для выездного обслуживания это было отслеживание местоположения в фоновом режиме.

Мы используем Pigeon для типобезопасных каналов платформы вместо сырых MethodChannels. Pigeon генерирует шаблонный код для обеих сторон (Dart и нативной) из одного определения интерфейса. Это исключает сопоставление методов на основе строк, которое вызывает ошибки во время выполнения, и делает код каналов платформы по-настоящему поддерживаемым.

Наше правило: если существует плагин с оценкой 90%+ на pub.dev и активным обслуживанием, используйте его. Если нет, напишите тонкую оболочку канала платформы, которая делегирует работу нативному API. Никогда не боритесь с платформой — обнимайте её через чистые мосты.

Стратегия тестирования, которая действительно работает

Инструменты тестирования Flutter отличные, но недостаточно используются. Наша пирамида тестирования: 60% модульных тестов (хранилища, контроллеры, бизнес-логика), 30% тестов виджетов (отрисовка компонентов и взаимодействие), 10% интеграционных тестов (критические пользовательские потоки от начала до конца). Это соотношение даёт нам уверенность в рефакторинге без хрупкости слишком большого количества интеграционных тестов.

Функция тестирования файлов-образцов недооценена. Для экранов со сложными макетами мы снимаем снимок отрисованного виджета и сравниваем его с эталонным изображением. Это выявляет визуальные регрессии, которые пропускают модульные тесты. Мы запускаем тесты файлов-образцов на CI для каждого pull request.

Выбрали бы мы Flutter снова?

Да, с оговорками. Flutter — лучший кроссплатформенный фреймворк на сегодняшний день для приложений, которым нужны и iOS, и Android с общей кодовой базой. Язык Dart производителен, а система виджетов действительно хорошо спроектирована. Hot reload делает итерацию быстрой.

Но это не правильный выбор для всего. Приложения, состоящие на 50%+ из платформоспецифичного кода (тяжелый AR, сложные конвейеры камер, глубокая интеграция с ОС), должны быть нативными. Приложения, которые в основном отображают контент с минимальной интерактивностью, могли бы использовать React Native или даже PWA. Flutter сияет для интерактивных, управляемых данными приложений с умеренными потребностями в интеграции платформ — что описывает большинство стартап-продуктов.

Mortgy

Founder & CEO

Flutter в продакшене: Что мы узнали после выпуска 3 кроссплатформенных приложений | iHux