inVerita и ее команда разработчиков мобильных приложений постоянно изучают производительность кроссплатформенных мобильных фреймворков, доступных на рынке, чтобы ответить на вопрос, какая технология лучше всего подходит для вашего продукта. Так мы и решили сравнить Flutter, React Native и нативную разработку.
Да, можно заметить, что React Native не выполняет никаких действий непосредственно на процессоре, и очевидно, что тяжелые задачи лучше будут работать у Flutter или Native приложений. Поэтому в этой статье мы решили исследовать производительность пользовательского интерфейса, которая оказывает гораздо большее влияние на повседневного пользователя мобильных приложений.
Измерение производительности пользовательского интерфейса является сложным и требует от инженера одинаковой реализации одинаковых функций на всех платформах. Мы использовали GameBench в качестве инструмента тестирования, чтобы не сомневаться и быть уверенными в том, что мы остаемся объективными (это не меняет того факта, что мы действительно любим Flutter в большинстве аспектов :), и по-прежнему выполняем множество проектов на React Native и нативной разработке). В GameBench есть много возможностей для улучшений, но нам удалось поместить каждое приложение в единую среду тестирования, что и было нашей целью.
Исходный код открыт, поэтому, пожалуйста, поэкспериментируйте и поделитесь своими мыслями с нами, если хотите. В UI-анимациях в основном используются разные инструменты на разных платформах, поэтому мы сузили все до библиотек, поддерживаемых каждой платформой (кроме одного случая), или, по крайней мере, мы сделали все возможное, чтобы добиться этого. Результаты тестирования могут отличаться и зависеть от ваших подходов к использованию тестов. Мы считаем, что вы, как потенциально истинный эксперт по конкретной технологии, можете довести свой конкретный набор инструментов до тех пределов, когда он превзойдет наши показатели, и мы будем рады, если вы это сделаете. Теперь давайте посмотрим на тесты.
Для тестирования мы использовали доступные Xiaomi Redmi Note 5 и iPhone 6s.
Репозиторий с исходным кодом находится тут.
Пример 1: бенчмарк списка
Мы реализовали один и тот же интерфейс для Android и iOS с использованием Native, React Native и Flutter. Мы также автоматизировали скорость прокрутки с помощью RecyclerView.SmoothScroller на Android. На iOS и React Native мы использовали подход с таймером и программной прокруткой до позиции. На Flutter мы использовали ScrollController для плавной прокрутки списка. В каждом случае у нас было 1000 элементов в списке и одинаковое время прокрутки для достижения последнего элемента списка. В каждом из этих случаев мы использовали кэширование изображений с разными библиотеками для каждой платформы.
Библиотеки загрузка и кеширования изображений:
- iOS — Nuke
- Android — Glide
- React Native — React-native-fast-image
Android
- Все тесты показали примерно одинаковый FPS.
- Android Native использует вдвое меньше памяти по сравнению с Flutter и React Native.
- React Native больше всего использует процессор. Причина заключается в использовании JSBridge между JS и Native code, что приводит к потере ресурсов на сериализацию и десериализацию.
- Что касается эксплуатации батареи, Android Native имеет лучший результат. React Native отстает как от него, так и от Flutter. Запуск непрерывной анимации потребляет больше энергии аккумулятора на React Native.
iOS
- FPS. React Native результаты хуже, чем у Flutter и Swift. Причина заключается в невозможности использования IoT-компиляции на iOS.
- Объем памяти. Flutter почти соответствует родному в потреблении памяти, но все еще тяжел в работе процессора. В этом тесте React Native сильно отстает от Flutter и native.
- Разница между Flutter и Swift. Flutter активно использует CPU, тогда как нативный код активно использует GPU. Согласование во Flutter увеличивает нагрузку на процессор.
Пример 2: тяжелые анимации
В настоящее время большинство телефонов, работающих на Android и iOS, имеют мощную аппаратную начинку. В большинстве случаев, используя обычные бизнес-приложения, вы не заметите никакого падения FPS. Вот почему мы решили провести несколько тестов с тяжелой анимацией. Достаточно тяжелой, чтобы получить снижение FPS. Мы использовали векторные анимации Lottie для нативного кода в Android, iOS и React Native, и использовали те же анимации с Flare во Flutter.
Тестирование анимации с помощью Lottie для нативного кода Android, iOS, React Native и Flare для Flutter:
Android
- Нативный Android и React Native имеют схожую производительность. Это очевидно, потому что Lottie для React Native использует нативные средства (16–19% CPU, 30–29 FPS).
- Результат Flutter стали сюрпризом (12% CPU и 9 FPS). Мы обнаружили, что удаление одной конкретной анимации из макета увеличивает FPS до 40% на Flutter. Мы предполагаем, что Flare тяжелее и не оптимизирован для такого рода задач, поэтому у Flutter было такое проседание FPS. Вот виновник:
- Нативный код требует меньшего объема памяти (205 Мб); React Native требует 280 Мб, а Flutter — 266 Мб.
- Холодный старт приложения. По этому показателю Flutter является лидером (2 секунды). Для Android Native и React Native старт занимает около 4 секунд.
iOS
- Результаты нативного кода и React Native в этом тесте почти такие же, так как Lottie в React Native использует нативный код.
- Flare и Flutter не перестают удивлять. Flare определенно есть куда улучшаться :D
- iOS Native требует наименьшего объема памяти (48 Мб). React Native требует 135 Мб, а Flutter — 117 Мб.
- Холодный старт приложения. По этому показателю Flutter является лидером (2 секунды). Для нативного кода и React Native он занимает около 10 секунд.
Пример 3: еще более тяжелые анимации с поворотами, масштабированием и затуханием
В этом тесте мы сравнили производительность анимации 200 изображений. Анимации вращения и мерцания выполняются одновременно.
Android
- Нативный код показал высочайшую производительность и наиболее эффективное потребление памяти.
- Flutter показал очень близкий к Native FPS и вдвое больший расход памяти, но все же приличную производительность.
- React Native в этом случае показал низкую производительность.
iOS
- iPhone 6s достаточно мощный, чтобы не снижать FPS во всех 3 случаях.
- Нативный код использовал меньше ресурсов и в основном использовал GPU.
- React Native в основном использовал процессор для рендеринга, в то время как Flutter использовал GPU.
- React Native использовал немного больше памяти.
Выводы
Для обычных бизнес-приложений с незначительной анимацией и хорошим внешним видом технологии не имеют никакого значения. Но если вы делаете некоторые тяжелые анимации, имейте в виду, что нативный кода дает наибольшую производительность. Далее идут Flutter и React Native. Мы бы определенно не рекомендовали бы использовать React Native в операциях, очень нагружающих CPU, в то время как Flutter отлично подходит для таких задач, как с точки зрения процессора, так и с точки зрения памяти.
Выбор инструмента зависит от вашего конкретного продукта и бизнес-ситуации. Если вы хотите разработать MVP для одной платформы — используйте нативные средства, но имейте в виду, что приложения Flutter могут создаваться как для мобильных устройств, так и для веб, и создается впечатление, что Flutter может стать королем кросс-платформенной разработки в не слишком отдаленном будущем, так как даже сейчас Flutter показал очень достойные результаты и уже может стать альтернативой нативным инструментам разработки (особенно если ваш бюджет на разработку не слишком большой).
Есть много факторов, влияющих на реализацию и тестирование каждой технологии, и многие из вас могут извлечь гораздо больше из любимых фреймворков. Мы постарались максимально повысить прозрачность процесса, создав единую среду для каждого тестируемого приложения и использовали единый набор инструментов для измерения производительности. Я надеюсь, что вам понравился результат.