Техника
Руководитель DevOps Отдела
Flutter — это технология, которая в настоящее время вызывает ажиотаж в мобильной разработке. Его стали чаще выбирать для создания новых приложений, а некоторые разработчики переписывают на Flutter даже старые приложения, по сути, без каких-то видимых на то причин.
Я провел с Flutter несколько месяцев на продакшн проекте, и хочу поделиться опытом, сравнив его с React-Native, с которым у меня довольно богатый опыт.
Я хотел бы подробно остановиться на том, что, что вам нужно учитывать, если вы переходите на кроссплатформенный нативный подход, и хотите понять, что вам больше всего подходит — Flutter или React-Native.
Обычно у вас есть 3 варианта мобильного приложения: полностью родное с Kotlin / Swift, полностью веб-приложение (PWA или контейнер WebView) и что-то среднее. Мы называем этот вариант Cross Platform Native, поскольку это не веб-приложения, а Native Apps, которые тем не менее используют кроссплатформенный подход.
Обе технологии предоставляют схожие возможности, однако использовать Flutter немного рискованно сейчас из-за его незрелости, недостатка библиотек и не очень большого пока ещё сообщества.
Я не буду углубляться в суть технологий, а оценю их с точки зрения применения в проектах и их возможностей в целом. Я рассмотрел следующие аспекты:
Обе технологии — кроссплатформенные и используют один и тот же подход: у них есть собственные части для Android и iOS, и включают кроссплатформенные среды выполнения, будь то JavaScript или Dart. Это можно представить следующим образом:
Обе платформы используют инструменты мобильной операционной системы для сборки: Gradle и Xcode build для Android и iOS соответственно. В этом плане разницы между ними и нативными приложениями нет.
Хотя есть разница в скорости сборки. Это не так важно для разработки, однако критично во время сборки CI и архивирования приложения в Xcode. У меня нет точных цифр, но у меня приложение «Hello, World» на Flutter собирается мерно в 3 раза быстрее, чем в React Native. Причина в том, что Flutter поставляется как iOS Framework, а React Native перекомпилируется из исходников.
Описанная выше архитектура означает, что необходимо преобразовать или скомпилировать общий код, включить его в окончательный apk / ipa и отправить результат в магазин приложений. Процесс может выглядеть следующим образом:
Однако между RN и Flutter всё же есть различия.
React Native поддерживает технологию Code Push, позволяющую отправлять обновления кода JS без повторной публикации apk / ipa из-за того, что React Native запускает пакет кода JS во время выполнения и может его заменить.
По сути, это можно считать некой проблемой безопасности. Команда Flutter, приняв это во внимание, вообще решили не поддерживать эту функцию.
Производительность следует рассматривать с нескольких точек зрения:
React Native использует родные виджеты платформы(Native Views) и передает события через JavaScript. Это влияет на производительность уровня представления, однако 60 fps в секунду все еще достижимы, хотя производительность зависит от версии ОС и самого устройства.
Flutter, с другой стороны, рендерит все, используя собственный 2D-движок Skia, избегая какого-либо специального соединения между вьюшками и другим кодом. Это делает рендеринг невероятно быстрым. У него могут быть проблемы с iOS, но эта проблема должна быть решена с помощью недавней поддержки Metal.
Сейчас я ничего не могу сказать, так как для этого требуется микробенчмаркинг обоих решений на разных устройствах. Это тема для отдельной статьи.
У React Native есть проблема с этим. Вообще, время запуска — это распространенная проблема, если вы стремитесь к совершенству своего мобильного приложения. RN должен загрузить виртуальную машину JS, а затем JS код. На Android это становится сложной задачей. Версия React-Native 0.60 обеспечивает поддержку Hermes: новой экспериментальной виртуальной машины JS для Android, которая предназначена для быстрой загрузки.
Flutter, кажется, уже решил эту проблему.
React Native работает с базовым протоколом http(s) с полифилом fetch, встроенной поддержкой WebSockets и богатые клиенты с axios (еще один пример чистой библиотеки js!) и rn-fetch-blob. React Native также парсит json из коробки, потому что это тоже JavaScript. Это также означает, что можно создавать свои типы с помощью Open Api.
У Flutter есть только встроенные клиенты http (s) и WebSockets. Клиент Axios находится в стадии разработки (я даже думаю о создании собственного, скажем, «fluxios»)). Парсинг JSON(конечно, если вы не используете кодогенерацию) нужно производить вручную. Поддержка открытого API существует, но она не обновлялась 15 месяцев. Существуют пакеты Dio и Chopper для упрощения работы с http, и скорее всего, появятся еще.
К сожалению, как оказалось, использование кодогенерации для openapi для Dart вызывает определенные проблемы, прочитать про которые можно тут.
React Native завязан на js и приложение на его основе содержит js bundle. Но его всегда можно извлечь и понять логику приложения, или изменить ее. Похоже, это серьезная проблема.
С Flutter гораздо сложнее изменить приложение, так как Dart код заранее компилируется в бинарный код для целевой архитектуры.
React Native использует пакеты NPM для включения зависимостей приложения, включая сам React Native. Помимо NPM, можно использовать Yarn для установки и управления своими зависимостями. Зависимости, которые требуют кода Kotlin / Java / Swift / Objective-C, связываются с помощью модулей gradle и пакетов CocoaPods. React Native включает функцию автоматической линковки, которая позволяет избежать ручного изменения файлов gradle и Podfile.
Flutter, в свою очередь, использует менеджер пакетов dart, также известный как инструмент pub. Пакеты поставляются в виде исходного кода и компилируются вместе с основным приложением. Как и в RN, эти пакеты могут иметь собственные зависимости, но в этом случае может потребоваться вручную добавить эти зависимости в файлы gradle и Podspec, хотя на практике лично я с этим не сталкивался. Можно также использовать неопубликованные пакеты, забирая их из папки или git репозитория.
React-Native имеет большую библиотеку компонентов пользовательского интерфейса: календари, средства выбора даты, кнопки, компоненты материалов, поддержку SVG и многое другое.
Flutter поставляется с компонентами Material и Cupertino из коробки. Но вот библиотека пользовательского интерфейса находится на ранней стадии. Возможно, с недостатком компонентов вы и не столкнетесь, однако количество библиотек компонентов для React Native намного больше. Это изменится в ближайшем будущем, поскольку все больше и больше разработчиков работают с Flutters.
Мне кажется, что в этом обе примерно технологии равны. Оба стека включают:
У React Native есть функция Fast Refresh, которая позволяет мгновенно видеть изменения на симуляторе / эмуляторе или реальном устройстве, это сокращает цикл обратной связи практически до нуля, в отличие от нативной разработки. Разработка обычно выполняется с помощью VSCode или WebStorm (это самые популярные инструменты). Оба включают в себя возможности для запуска и отладки кода, запуска тестов, просмотра покрытия и обеспечения автозаполнения. На мой взгляд у RN автозаполнение ограничено (я думаю, из-за JavaScript), поэтому я вернулся к запуску сборки либо с npx react-native run-ios или через Xcode, потому что запуск через WebStorm был очень нестабильным. Также время от времени падал сам упаковщик. Типичный способ отладки — это запуск Google Chrome и использование его консоли, что является неоптимальным.
У Flutter отличный DX. Поскольку это продукт Google, он позволяет интегрировать IDE (Android Studio, но я предпочитаю IntelliJ Idea как более стабильную) сразу с набором инструментов. Быстрая загрузка почти такая же, как и быстрое обновление, и даже лучше. Автозаполнение работает на ура, поскольку Dart строго статический и типизированный, что создает поддержку стабильности среды разработки IDE. Тут надо сделать замечание, что Dart из коробки предоставляет большую свободу в плане типов, вы можете их вообще не писать, поэтому рекомендуется его донастроить в своем проекте.
Кроме того Flutter показывает причины ошибок, поэтому их легко пофиксить. Отладчик в IDE тоже работает очень хорошо. VSCode также поддерживает Flutter, но не имеет функций отладки и VCS.
Обе технологии сильно зависят от базовых платформ. Никакие фреймворки для Android / iOS сами по себе ничего не делают в плане медиа, а скорее используют медиакомпоненты, доступные в системе. Вопрос лишь в том, насколько хорошо поддерживаются возможности платформы.
React Native поддерживает воспроизведение и запись как аудио, так и видео. Можно, например, показывать видео в разных форматах (в основном все они поддерживаются ExoPlayer (Android) и AVPlayer (iOS)), отображать элементы управления для поиска, зацикливания и т.д. Также можно отображать субтитры SRT и VTT для видео «из коробки». Этот функционал поставляется с такими компонентами, как react-native-video,react-native-video-controls и другими.
В основном Flutter имеет только пакет video_player для воспроизведения видео. Его версия 1.0 все еще находится на рассмотрении и может отображать все видеоформаты, предоставляемые мобильными ОС, а вот субтитры — только SRT, субтитры VTT отсутствуют в дорожной карте. VTT субтитры тем не менее поддерживается отдельным пакетом. Для основных элементов управления необходимо использовать пакет Chewie.
Как всегда, выбор зависит от нефункциональных требований, но я бы рекомендовал при этом учитывать: