Flutter: плюсы и минусы использования кросс-платформенной технологии

Аватарка пользователя Илья Задябин

Рассказали на примере Flutter, как на самом деле обстоят дела в мире кросс-платформенной разработки, и назвали все плюсы и минусы.

Принято считать, что кросс-платформенные технологии могут облегчить жизнь программистам: забудьте про мучения в разработке приложений сначала под iOS, а потом под Android и еще отдельно под Web. Однако, если бы все было столь просто, миром программирования давно бы всецело управляли кросс-платформы. Как обстоят дела на самом деле рассмотрим сегодня на примере Flutter.

Илья Задябин, разработчик мобильных приложений, специализирующийся на Flutter и Dart.

Что такое Flutter, в чем особенности этой технологии

Flutter — это открытая кросс-платформенная технология от Google, предназначенная для создания приложений для iOS, Android, Web и настольных операционных систем из единой кодовой базы. Она использует язык программирования Dart и предоставляет свой собственный набор виджетов для создания интерфейса. Сейчас Flutter поддерживает iOS, Android, Web, Windows, Linux, macOS и с недавнего времнени WebAssembly.

В основном Flutter применяют для мобильных приложений, потому что фреймворк достаточно недавно обзавёлся поддержкой остальных платформ. Также Flutter поддерживается на “встраеваемых устройствах” (embedded devices), например, Toyota использует эту технологию для мониторов в своих автомобилях.

Технология зарекомендовала себя на рынке и используется в широком спектре приложений. Например, в приложении для электромобилей BMW, Google Pay – команда провела миграцию с нативного кода на Flutter прежде чем выйти на глобальный рынок, Ebay, ByteDance, NuBank, а также в Alibaba.

Теперь немного про “внутренности” Flutter и про то, почему вообще возможно запускать один и тоже же код на принципиально разных платформах.

Было бы очень сложно и долго подстраивать технологию под разные API этих платформ, поэтому команда Flutter пошла другим путём.

1. Архитектура

Flutter использует многоуровневую архитектуру. Верхний слой – фреймворк, состоящий из кода на языке Dart. Нижний слой – движок, написанный преимущественно на языке C++ и обеспечивающий низкоуровневую реализацию основных API Flutter. Наконец, есть Embedder, который интегрирует движок Flutter в различные платформы.

2. Процесс рендера

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

3. Компиляция

Flutter использует язык Dart, который компилируется в нативный код. Компиляция в нативный код позволяет Flutter взаимодействовать с платформой без моста JavaScript (как в некоторых других кросс-платформенных решениях), что обеспечивает производительность, близкую к нативной.

4. Виджеты

Everything in Flutter is a widget, от простого текста до сложной анимации. Эти виджеты не являются родными компонентами Android или iOS, но настроены так, чтобы выглядеть как родные элементы. Из виджетов, как из кирпичей, собирается всё приложение. Такая система может быть более понятной для новых разработчиков.

5. Platform Channels

Для доступа к специфическим для платформы функциям (камера, GPS, микрофон…) Flutter использует Platform Channels. Эти каналы позволяют приложениям Flutter выполнять действия на iOS или Android с использованием их родных языков программирования (Kotlin для Android, Swift для iOS).

Декларативное VS императивное программирование

Одной из особенностей Flutter является декларативный стиль описания UI элементов. Сперва про отличия:

  • Декларативное программирование. Основное внимание уделяется вопросу “что” в коде. Вы описываете то, ЧТО хотите получить, а система (фреймворк или библиотека) занимается деталями того, как это реализовать. Этот стиль абстрагирует процесс управления UI, и разработчику не нужно описывать шаги для достижения конечного результата. 
  • Императивное программирование. Концентрируется на “как”. Процесс состоит из написания кода, описывающего шаги для достижения цели. Разработчик должен описать каждый шаг, который должна выполнить программа, что дает ему больше возможностей для контроля, но также увеличивает сложность. 

Итак, Flutter использует декларативный подход к построению UI. Вот как это работает: UI является отражением состояния. Вы определяете состояние, а пользовательский интерфейс автоматически адаптируется и рендерится в соответствии с этим состоянием. Это означает, что при изменении состояния Flutter точно знает, что изменилось, и может эффективно (быстро) обновлять пользовательский интерфейс.

Для построения пользовательского интерфейса используется дерево виджетов. Каждый виджет декларирует часть UI, а всё дерево в целом представляет весь интерфейс. При каждом изменении состояния Flutter автоматически перестраивает дерево виджетов, обеспечивая отображение 1:1 текущего состояния и пользовательского интерфейса.

В отличие от этого, традиционная разработка под Android и iOS использует императивные подходы:

  • Android. XML-файлы определяют элементы пользовательского интерфейса, которые затем используются в коде на Kotlin. Разработчики явно изменяют свойства компонентов UI и управляют его состоянием.
  •  iOS. С помощью UIKit разработчики создают и управляют компонентами UI (например, UIViews) в Swift. Они отвечают за обновление и рендеринг этих компонентов в зависимости от взаимодействия с пользователем или изменения данных.

На данный момент Android и iOS тоже переходят к декларативному стилю, используя Jetpack Compose для Android и SwiftUI для iOS. Оба инструмента находятся в активной разработке.

Язык Dart и его особенности

Во Flutter используется Dart – современный объектно-ориентированный язык программирования, разработанный Google. По словам создателей, Dart оптимизирован для создания пользовательских интерфейсов: в нём используется async-await для изменения UI, в сочетании с возможностью запускать код изолированно от основного потока. Dart использует типизацию с null-safety, сборщик мусора и имеет схожий синтаксис с kotlin, swift, typescript, что делает его простым в изучении.

Одним из ключевых преимуществ Dart является Hot Reload. Из-за возможности Dart компилироваться в двух режимах AOT (ahead of time) and JIT (just in time) язык позволяет динамически обновлять приложение без необходимости перезапуска. Можно мгновенно видеть, как поменялся UI при изменении кода, что очень удобно и ускоряет разработку.

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

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

Плюсы использования кросс-платформы

Есть целый ряд неоспоримых преимуществ использования кросс-платформенной технологии:

  1. Гораздо более дружелюбная документация по сравнению с Android и особенно iOS, разработчики Flutter также выпускают еженедельные видео с объяснениями деталей технологии на своём официальном канале.
  2.  Общий код для разных платформ. Flutter позволяет разработчикам использовать один и тот же код для создания приложений для разных платформ, снижая время и стоимость разработки.
  3. Hot Reload. Эта функция позволяет мгновенно видеть результаты изменений в коде, ускоряя процесс разработки.
  4.  Фреймворки внутри фреймворка. Команда Flutter развивает направление мобильных игр и предлагает воспользоваться Casual Games Toolkit , в котором есть необходимые инструменты для написания собственных игр на 2D движке Flame. Также есть готовый набор решений для написания новостных приложений Flutter News Toolkit. В нем содержатся наиболее популярные компоненты для создания news app: онбординг, создание учетной записи, лента контента и страницы контента, настройки монетизации, поиск и т.д. 
  5. Экосистема библиотек. Ещё один из плюсов Flutter сообщества – это наличие единого сервиса, на котором хостятся сторонние библиотеки. Они используются далеко не только для работы с нативным кодом платформ, но и для сложных анимаций, облегченной работы с сетью, навигации и полезными инструментами. Любой желающий может создать свой пакет и разметить его на pub.dev. 

Ограничения использования кросс-платформы и пути их решения

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

Проблема №1. Большой размер приложения

Приложения Flutter могут иметь больший размер файла по сравнению с нативными приложениями. Можно использовать стандартные средства для сжатия ресурсов и ассетов. Также для Android есть возможность догрузить ассеты после установки через Сloud delivery of assets.

Проблема №2. Несоответствие “родному” пользовательскому интерфейсу

Достичь “родного” поведения экрана может быть сложно, так как Flutter управляет собственным рендерингом. Для решения этой проблемы можно настроить виджеты таким образом, чтобы они в точности соответствовали языку дизайна каждой платформы, и следить за последними тенденциями и рекомендациями по UI для iOS и Android. Большая часть компонентов уже подогнаны командой Flutter под привычный UI платформы.

Проблема №3. Задержка при появлении обновлений платформ

Иногда в iOS или Android может появиться новая функциональность (например, dynamic island в iOS) и приходится ждать, пока её завезут во Flutter. Благо такие обновления не носят критический характер, а чаще всего другие разработчики оперативно создают пакет для работы с новыми возможностями платформы.

Проблема №4. Невозможность разработки мобильных игр

Flutter не оптимизирован для 3D игр, но есть возможность создавать 2D игры, используя движок Flame, о котором написано выше.

Проблема №5. Ограниченная поддержка некоторых функций устройств.

Некоторые встроенные функции устройств могут быть недоступны или требуют дополнительной работы для интеграции. Из-за того, что Flutter не использует активно API платформы, а просто отрисовывает самостоятельно нужные элементы, могут возникнуть проблемы с доступом к функциями устройства, таким как камера, уведомления, микрофон, GPS, шифрованная память и т.д. Для решение этой проблемы можно использовать platform channels, которые позволяют вызывать код платформы (например, Kotlin для Android или Swift для iOS) прямиком из кода Flutter. Это усложняет процесс разработки, потому что помимо языка Dart ещё нужно понимать, как устроена платформа, код в которой нужно вызывать напрямую. Но такие ситуации редки, потому что для большинства случаев уже написаны packages (сторонние библиотеки) членами сообщества.

Есть и еще одна особенность, о которой мы уже говорили ранее – язык программирования. Dart – нишевый язык, изначально разрабатывался Google как замена JavaScript, но что-то пошло не так. Язык оставался в тени, пока в 2017 году Google не создали на его основе фреймворк Flutter, тем самым дав ему второе дыхание. Dart похож на JavaScript, поэтому будет понятен и большинству новичков, и опытным разработчикам.

Недостатки языка Dart компенсируются кодогенерацией, к примеру в языке отсутствуют дата классы (аналог data class в Kotlin), но при помощи сторонних пакетов можно воспроизвести нужные методы, сгенерировав их для обычных классов Dart. Также кодогенерацию можно использовать для сериализации/десериализации. В Dart даже есть аналог Retrofit, который будет знаком разработчикам Android. До недавнего времени разработчики генерировали даже функциональность sealed классов, но их ввели в Dart 3, и необходимость отпала.

Ещё один из плюсов Dart это возможность замкнуть на нём весь цикл разработки приложения и использовать Dart для написания backend при помощи Dart Frog. Тем самым язык может стать более популярным и привлечь больше разработчиков, что скажется в положительном ключе на развитии Flutter.

Flutter
Dart
1450