Мобильное приложение на Flutter, часть вторая: стоимость, сроки, подводные камни

Мы в Mad Brains очень внимательно подходим к выбору технологий разработки, поэтому к кроссплатформе шли несколько лет. Нас постоянно в ней что-то не устраивало: набор компонентов, производительность, выразительность языка.

К Flutter мы присматривались почти 2 года, выискивая недостатки, но в итоге сделали ставку именно на него, почему, расскажем в деталях ниже.

О чем статья

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

Как устроены кроссплатформенные фреймворки?

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

  1. «Приложения-браузеры» — Cordova, PhoneGap, Ionic — мобильный сайт, завернутый в оболочку приложения с единственной веб-страницей, растянутой на весь экран. Все проблемы мобильного сайта остаются на месте, попытки сделать html-компоненты похожими на стандартные работают с переменным успехом, JS опять же.
  2. «Сделай сам» — Qt и C++, Kotlin Multiplatform — как езда на машине с ручной коробкой передач по бездорожью... с педальной тягой... и табуретом вместо кресла. Есть доступ к самому низкому уровню, где почти нет ничего готового. Либо нужно писать все самостоятельно, вплоть до отрисовки внешнего вида кнопок, либо реализовывать отдельно для каждой платформы связь со стандартными компонентами. Получить выгоду в таком подходе получается только для специфических задач, обычно все наоборот.
  3. «Уравнители» — Xamarin, React Native — решения, которые стараются магическим образом преобразовать свой код в стандартные компоненты платформ. Этот подход напоминает телевизионную игру «Стенка на стенку», где игроку нужно встать в такую позу, чтобы попасть в нужную форму. Только в данном случае формы сразу две, а поза одна. Например, если в iOS есть возможность добавить кнопке тень и закругление, а в Android — обводку и закругление, то может случиться, что получится воспользоваться только закруглением, а остальное придется делать отдельно для каждой платформы.
  4. «Дайте холст, мы со своим пришли» — Unity и пр. игровые движки, Flutter–подход чем-то похож на первый тип, но за основу берется не веб-страница, а самый низкий уровень из возможных — уровень отрисовки на экране. Другими словами, фреймворк буквально управляет состоянием каждого пикселя максимально близко к железу, а не пытается найти похожий элемент в каждой платформе. Так чем же это лучше подхода «Сделай сам»? По факту только тем, что все сделано за нас и этим можно удобно пользоваться, как машиной с автоматической коробкой передач, да еще и с климат-контролем.

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

Как работает Flutter?

Немного технических деталей реализации. На самом верхнем уровне мы оперируем виджетами (Widget). В корне Flutter идея, что все есть виджет (не без исключений, конечно же). Виджеты отрисовываются на канвасе с применением графической библиотеки Skia и отправляются на обработку платформе. Платформа отображает канвас и пересылает обратно события (пользовательское взаимодействие, данные с датчиков и тп.).

Наглядная демонстрация технических деталей работы Flutter
Наглядная демонстрация технических деталей работы Flutter

Такое взаимодействие можно условно разделить на 3 слоя.

Flutter system overview
Flutter system overview

Embedder — самый низкий уровень, непосредственный контакт с платформой. Определение потоков для работы, переадресация событий и прочие низкоуровневые вещи, которые транслируют данные и события между миром Flutter и платформой. Для каждой платформы (iOS, Android, Web, Desktop) эта часть пишется отдельно.

Engine — базовая часть Flutter, оптимизированная и написанная на C/C++, но уже не зависящая от платформы. В нее входит дальнейшая переадресация данных и событий, отрисовка с помощью библиотеки Skia, работа с изолятами и прочие низкоуровневые процессы самого Flutter.

Framework — то, с чем мы непосредственно работаем в момент создания приложения. Готовые виджеты для создания интерфейса, управление лейаутом, отрисовкой и состоянием деревьев виджетов, элементов и рендер объектов.

Общая картина выглядит так, конечно, есть еще огромное количество деталей и нюансов, каждый из которых достоин отдельной статьи.

Поддержка новых версий операционных систем

Поддержка приложений на Flutter также упрощена. Если в очередной версии iOS появляются новые визуальные компоненты, то увидеть их смогут те, кто обновил свои девайсы, в то время как во Flutter можно получить аналогичный компонент у всех пользователей на всех операционных системах, как только его реализует команда Flutter, а происходит это быстро.

Другим вариантом может стать воссоздание компонента самостоятельно из готовых вариантов или подсмотрев исходники — они находятся в открытом доступе. Поддержка Material Design во Flutter-компонентах на данный момент реализована полнее, чем на Android, для которого этот Material Design и придумывался в свое время.

Поддержка аппаратных функций

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

А как же нативные компоненты?

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

Производительность

Кроссплатформенные решения прошлых поколений научили нас, что за универсальность приходится платить. Чаще всего под нож попадает производительность приложения. Достаточно вспомнить проблемы со скроллом в React Native. Резонно задаться вопросом, как дела с производительностью у Flutter?

Сами разработчики отвечают на этот вопрос так:

“You can expect excellent performance. Flutter is designed to help developers easily achieve a constant 60fps.”

— Вы можете ожидать отличную производительность. Flutter разработан таким образом, чтобы помочь разработчикам легко достигать стабильных 60 кадров в секунду.

Код Dart компилируется в нативный, а это означает отсутствие трат ресурсов на интерпретацию кода во время выполнения. Виртуальная машина Dart приспособлена для создания и уничтожения огромного количества объектов, что позволяет работать с огромным количеством визуальных элементов на экране без каких-либо проблем. Графический движок Skia специализируется на работе с 2D-графикой и позволяет отрисовывать все с частотой 60 кадров в секунду.

Это все прекрасно, но давайте посмотрим на числа. В интернете легко можно найти 2 независимых исследования этой темы:

  • Коллеги из inVerita в своем материале сравнили вычислительную мощность Dart с нативными языками, а также производительность UI-компонентов Flutter, React Native и натив на iOS и Android. Вывод вполне ожидаемый — нативные решения в среднем оказались наиболее производительными, но Flutter и Dart не сильно отставали, а местами даже опережали натив, чего не скажешь о React Native.
  • Bram De Coninck написал про то, как сначала сделал одинаковое приложение на Xamarin Forms, React Native, Flutter, iOS и Android. А затем сравнил их производительность. В данном эксперименте Flutter опять показал себя близким по производительности к нативным реализациям, а Xamarin Forms и React Native снова остались не у дел. В данном исследовании интересно принять во внимание еще и первую часть со сравнением времени, потраченного на реализацию, оно тоже вполне сопоставимо с написанием приложения под нативную платформу — одну. А в случае с Flutter мы получаем реализацию сразу на 2 платформы, то есть примерно в 2 раза быстрее.

Исключительные черты Flutter

Помимо всего перечисленного, есть еще несколько вещей, выделяющих Flutter:

  • Open Source. Открытый код, доступный для изучения и изменения. Можно без труда понять, что происходит внутри, и даже поправить при желании. Если Google решит отказаться от этого проекта, он будет жить за счет сообщества.
  • Инструменты. Очень удобные компоненты, значительно упрощающие работу. Один из них hot reload. Теперь не нужно после каждого изменения ждать компиляции и запуска приложения для проверки.
  • Документация. Подробная документация по каждому аспекту, информативные видео на YouTube, мероприятия и конференции — постоянные потоки полезной информации со всеми разъяснениями.
  • Проверенные подходы. Архитектурная часть взята с проверенных на вебе решений. Это позволило не изобретать велосипед, а опираться на опыт прошлых мировых разработок. Для мобильных разработчиков это непривычно, т.к. они привыкли изобретать новую архитектуру каждый год, что в узких кругах это стало своеобразным мемом. Пора уже использовать что-то проверенное.
  • Производительность. Самый низкий уровень отрисовки, управление каждым пикселем, использование Skia под капотом (графическая библиотека, давно зарекомендовавшая себя), никакой интерпретации на лету - только компиляция в машинный код. На выходе - 60 кадров в секунду, работа без задержек.

Все это делает Flutter идеальным кандидатом для быстрой и качественной разработки в сжатые сроки кризисных реалий.

Ложка дегтя

Чтобы не появилось мысли, что Google доплачивал за эту статью, расскажем о минусах.

  • Новизна технологии. Есть у всего нового свои детские болезни. Не обошло это стороной и Flutter, особенно в первое время после официального релиза, когда все обратили особое внимание на технологию. Баги есть везде, но в данном случае они воспринимаются как что-то очень критичное, так как кредита доверия еще не образовалось, большие игроки на тот момент еще не включились в игру. Сейчас с этим лучше, сообщество растет, ошибки активно исправляются. Только в последнем релизе было влито более 3000 исправлений.
  • Dart. Главная боль для любого мобильного разработчика, избалованного Kotlin и Swift. Отдельный язык программирования, который отстает от крутости последних наработок Kotlin и не дотягивает до лаконичности Swift. Да и специфика однопоточности языка накладывает свои сложности в понимание, как с этим работать.
  • Нехватка кадров. Из вышеперечисленного вытекает, что найти разработчиков, особенно опытных, непросто. Хорошо, что в IT-сфере люди привыкли постоянно обучаться и искать новые подходы и решения. Так, например, Flutter из-за своей специфики позволяет быстро влиться не только мобильным разработчикам, но и веб-разработчики находят много привычного и удобного.

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

Выводы

Flutter — молодой SDK, у которого есть шанс стать первым массовым кроссплатформенным решением. Да, он не идеален, но наиболее близок к нему.

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

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

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

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

Например, если потребуется, чтобы Tab Bar превращался в боковую панель при повороте, то Flutter сделает это легко, в то время как на нативе это заставит помучиться. Благодаря всему этому, разрабатывая на Flutter, программисты экономят время, а клиент — бюджет.

Другие статьи из этой серии

1515
20 комментариев

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

Я бы этот пункт отнес бы к веб разработке, а не мобильной, потому что то количество фреймворков и надстроек над джс за последние пять лет это надо было нафантазировать. В мобильной разработке, если брать в учёт только нейтив платформы, то радикально разработка не меняется особо...

1

JS-ники любят писать по 10ку новых библиотек каждый день, да. Мобильщики же просто буквы тасуют в аббревиатурах(MVVM, MVP, MVI, VIPER и тп), по сути не сильно уходя от MVC

1

много ошибок в статье.
Kotlin multiplatform вообще не о том
flutter не компилируется в нативный код. Он работает в своей VM, которая уже работает в VM платформы.
и т.д.

1

От VM там одно название. По факту только управление изолятами, сборщик мусора и еще какие то мелочи. А так что сама VM, что дарт код собираются в нативный бинарь и исполняются напрямую AOT компилятором. Полноценная VM с JIT компиляцией используется только для дебага.
Под тем же андроидом приложение компилируется в .so библиотеку, даже не далвик байткод.

1

Давайте разбираться и приходить к правильному общему мнению, не спорю что мы можем ошибаться
1) Kotlin Multiplatform упомянут тут в контексте одного из вариантов шаринга кода между платформами. Да, он не про UI совсем, но все же позволяет например использовать один язык на iOS и Android. 
2) Да, часть VM остается, но внутри скомпилированной в натив (x86 или ARM) библиотеки. https://dev.to/jay_tillu/flutter-compilation-process-41k0
Есть еще какие-то неточности на ваш взгляд?

Про флаттер начинают говорить из каждого утюга)
Почему-то не написали про серьезное преимущество - существенно "сократили" жизненный цикл UI-элементов. Во флаттер по сути экран каждый раз перерисовывается заново, это оказалось удобно. Мы в www.xmall.space на основе этой концепции разбили приложение на отдельные модули, которые можно тасовать как хочет клиент. На выходе получаются совершенно разные приложения за короткий срок, которые на нативе делать было бы гораздо сложнее.

1

Согласен, важное преимущество! Не упомянули только потому что пришлось бы вдаваться в технические детали реализации памяти Dart, чтобы объяснить почему это переделки всего UI на каждый кадр (почти) работают так быстро. Можем разобрать в следующей статье