14 мая Flutter зарелизили новую версию 3.22. Подробнее об этом тут (мы всё заботливо перевели и художественно отредактировали), оригинал здесь

Наша Flutter-команда не могла остаться в стороне и уже опробовала новинку. Делимся мнением.

Марк Абраменко, Engineering Manager во Flutter-отделе Surf

Макросы в Dart

Забавно, но на секции QnA на московском митапе Flutter от нашей команды, когда отвечал на вопрос про статическое метапрограммирование, я сказал, что вряд ли нам стоит ждать этого в ближайшие годы. 

И всего через 3 недели команда Dart анонсирует использование макросов в языке. 

Именно анонсирует, потому что на самом деле макросов в Dart 3.4 нет. Чтобы их попробовать, нужно переключиться минимум на 3.5.0-152 dev-канала, либо на master-ветку (!) Flutter. 

В статье, кстати, фичу пообещали выкатить только к началу 2025 года. 

Команда Dart в анонсе пообещала выкатить отдельный язык (набор ключевых слов), который будет использоваться для написания макросов. Сейчас же они выпустили первый пакет, который использует макросы — json. В пакете уже можно найти новые ключевые слова: 

  • macro — для объявления аннотации;

  • augmented — для просмотра результата генерации.

Интересно, что название пакета “json” держали целых 10 лет для этого апдейта: 

Несмотря на то, что эта фича находится в зачаточном состоянии, работает всё достаточно неплохо. 

Чтобы попробовать JsonCodable, нужно пройтись по официальной инструкции: поставить определённую версию Dart и Flutter, выставить флаги experimental, добавить пакет json. 

В VSCode с предрелизными версиями плагинов уже всё работает достаточно неплохо: плагин понимает новые ключевые слова, работает предпросмотр генерации кода, анализатор не ругается на “неявные” методы (toJson, fromJson). 

Некоторые справедливо критикуют аналоги статического метапрограммирования (рефлексию, мирроринг) за то, что она лишает нас безопасности на уровне компиляции — что-то точно может «выстрелить» в рантайме. Фича с «предпросмотром» сгенерированного кода привносит больше прозрачности в этот процесс. Если анализатор Dart будет работать с «предпросмотром», это значительно повысит привлекательность рефлексии по сравнению с другими языками.

Могу с уверенностью сказать, что рано или поздно такие пакеты как freezed, injectable и auto_route перейдут на кодогенерацию в рантайме. А в ближайший год мы с вами точно будем использовать build_runner. 

Блюр переписали с нуля?

Об исправлении блюра при работе с PlatformView нам поведали ещё в версии 3.7. И, на мой взгляд, тогда работать он стал хуже. Версия 3.22 исправила многие проблемы, но не все. 

Здесь небольшой проект с демонстрацией проблем на iOS при работе с PlatformView на примере работы с вьюшкой карт. Это экран со Scaffold, в body которого находится PlatformView с iOS. Сам Scaffold находится в Stack и его целиком перекрывает блюр. 

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

Второй пример демонстрирует типичное использование блюра — алерт на iOS. Раньше блюр просто не появлялся, если в зоне видимости есть PlatformView. 

В версии 3.7 блюр появился, но у него не было анимации. И это выглядело даже хуже, чем было раньше. В версии 3.22 проблему, наконец, исправили.

Третий пример — Flutter-виджет находится поверх PlatformView. В «исправлении» 3.7 мы видим странное поведение — виджеты блюрятся выборочно. 

Версия 3.22 частично исправляет это поведение. Выглядит всё ещё плохо.

Четвёртый пример — блюр с анимацией. Все 3 версии пока не отображают адекватное поведение. 

Максим Яковлев, Flutter-разработчик, Surf

Релиз WASM

Пожалуй, самое заметное изменение в релизе Flutter 3.22 и Dart 3.4 — это поддержка компиляции наших приложений в WebAssembly для исполнения их в браузере.

wasm — это не очередной убийца js и не будущая замена html/css/js.

WebAssembly — это технология, которая позволяет низкоуровневым языкам программирования, таким как С++, Rust, Go исполняться в безопасном контейнере, внутри браузера прямо на движке V8, так же, как это делает javascript.

Для простоты можно воспринимать его как FFI, но для веб‑приложений. И сфера применения довольно схожа.

Наверное, не лучшей идеей будет перенос в wasm модули простой бизнес‑логики: изменение цвета кнопки в UI, навигация, авторизация или http‑запросы. Это не даст ощутимых изменений производительности.

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

Получается, компиляция в Flutter приложений в wasm — отличная идея. Ведь все, что видит пользователь, отрисовывается силами SKIA и Flutter framework. А прирост скорости вычислений положительно сказывается на пользовательском опыте. 

Flutter engine, реализованный на С++, давно был скомпилирован в wasm и активно используется текущими приложениями. Это увеличило производительность и сократило время отрисовки кадра. Но анимации и скролл рассчитываются в Flutter framework слое, реализованном на dart. 

До недавнего времени компиляция языков со сборщиком мусора в WebAssembly была недоступна и эта часть движка компилировалась в js, что вызывало явный недостаток производительности.

Но теперь, благодаря совместным усилиям команды Dart, Chrome и других участников сообщества реализован стандарт WasmGC, который позволяет компилировать высокоуровневые языки программирования со сборщиком мусора в wasm. 

Благодаря чему, теперь все приложение, включая зависимости, компилируется в WebAssembly.

Мы были бы не мы, если бы не попробовали собрать одно из наших веб-приложений в wasm. 

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

Результат впечатляет:

Здесь видно, что отрисовка анимаций заметно улучшилась. В первом случае кадр рендерится только силами js. На выходе мы видим 2 кадра при открытии drawer menu. 

Во втором случае используется skia, скомпилированный в wasm. Дела тут чуть лучше, но отсутствие плавности и микрофризы интерфейса заметно. 

Последний пример — это версия приложения, скомпилированная полностью в WASM. Число кадров увеличилось чуть меньше, чем в 2 раза, в сравнении с skia wasm. 

Интерфейс веб-приложений стал намного плавнее и приятнее. Некоторые отметили, что шрифты и векторные изображения стали более сглаженные. В целом, внешний вид и опыт взаимодействия заметно приблизился к нативным приложениям. А это уже открывает дорогу по-настоящему классным PWA приложениям уже сейчас.

Но не все так расчудесно:

  • Полная поддержка WasmGC сейчас есть только в Google Chrome в версии 119 и выше;

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

А вот Safari вообще не поддерживает новый стандарт — так, все владельцы портативных девайсов от Apple не смогут оценить прирост производительности в приложениях.

Но стоит отметить, что команда Flutter обновила раннер для веб-приложений. Во время старта он проверяет возможности браузера и отображает либо js-версию, либо wasm skia, либо версию, полностью скомпилированную в wasm.

И отсюда — следующая проблема;

  • И без того «пухленькое» flutter приложение набрало еще больше веса. И теперь при холодном старте скачивается практически в 2 раза больше статических ресурсов в виде js-скриптов и wasm-модулей.

    Очевидно, что этот процесс можно оптимизировать. Но мы пока этим не занимались;

  • Возможна только релизная сборка приложения в wasm. 

    Мы не можем разрабатывать в режиме сборки wasm, отладка/профилирование будет доступна только посредством браузера в релизном режиме;

  • Dart не дает возможности напрямую взаимодействовать с wasm-модулями. Для этого необходима js-прослойка.

    Этот недостаток не позволяет использовать wasm за пределами js-среды

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

Больше полезного про Flutter — в Telegram-канале Surf Flutter Team. 

Кейсы, лучшие практики, новости и вакансии в команду Flutter Surf в одном месте. Присоединяйтесь!

Комментарии (14)


  1. Emulyator
    22.05.2024 12:21

    За флаттер не скажу, но кричащие на картинке птички остро напомнили старый киберспортивный мем "322", в двух словах означающий ставку на своё поражение. )


  1. Octabun
    22.05.2024 12:21

    Наша Flutter-команда не могла остаться в стороне и уже опробовала новинку.

    Ба! И я не смог остаться в стороне. EndeavourOS.

    > flutter create test
    > cd test
    > flutter run -d linux
    ..................
    ..................
    ** (test:1009283): CRITICAL **: 16:25:22.671: Failed to read XDG desktop portal settings: GDBus.Error:org.freedesktop.portal.Error.NotFound: Requested setting not found
    
    ** (test:1009283): CRITICAL **: 16:25:22.678: Failed to read XDG desktop portal settings: GDBus.Error:org.freedesktop.portal.Error.NotFound: Requested setting not found
    
    ** (test:1009283): CRITICAL **: 16:25:22.682: Failed to read XDG desktop portal settings: GDBus.Error:org.freedesktop.portal.Error.NotFound: Requested setting not found
    
    ** (test:1009283): CRITICAL **: 16:25:22.686: Failed to read XDG desktop portal settings: GDBus.Error:org.freedesktop.portal.Error.NotFound: Requested setting not found
    
    ** (test:1009283): CRITICAL **: 16:25:22.689: Failed to read XDG desktop portal settings: GDBus.Error:org.freedesktop.portal.Error.NotFound: Requested setting not found
    Syncing files to device Linux...                                    84ms
    

    Ага, CRITICAL... И что конкретно not found? Плюсик работает, следующее подозрение - ввод с клавиатуры, не проверял.

    Может я чего неправильно установил? Заглянем в инструкцию https://docs.flutter.dev/get-started/install/linux/desktop?tab=download

    Create a folder where you can install Flutter.

    Consider creating a directory at /usr/bin/.

    И тут же чуть ниже

    echo 'export PATH="HOME/development/flutter/bin:PATH"' >> ~/.bash_profile

    Разве Flutter заработает если его ставить точно по инструкции?

    Первый же контакт - и ощущаешь себя бредущим по колено в грязи... Вид цитаты вверху - результат копирования фрагмента кода соответствующей иконкой и его вставки под цитату в редакторе Хабра. Я специально ограничиваю исправления этим комментарием чтобы было понятно что такое ГРЯЗЬ. Должно быть

    echo 'export PATH="$HOME/development/flutter/bin:$PATH"' >> ~/.bash_profile


    1. MountainGoat
      22.05.2024 12:21

      Это ошибка не Flutter а GTK и похоже она навечно.


      1. Octabun
        22.05.2024 12:21

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

        Мне кажется, знаю что - нехватка людей и неграмотность, скорее детскость, в руководстве проектом. Они сами писали - мы отдали приоритет простым и понятным задачам которые можно решить быстро и в итоге пришли к тому что все оставшиеся задачи сложные и непонятные. Это детская ошибка, но команда учится. Вопрос: после недавнего, научившиеся остались в команде?

        Можно удивиться - как так у Гугла могут быть детские ошибки в руководстве проектами? Есть гипотеза - не всё в этом мире суть Интернет и раздача рекламы, для разных задач нужно разное мышление, а его носителями являются казные люди, иногда борющиеся друг с другом за влияние. Эта гипотеза хорошо объясняет размер "кладбища Гугол".


        1. MountainGoat
          22.05.2024 12:21

          Это ошибка GTK и GTK пишет эту надпись. Вызвана тем, что GTK конфликтует с xdg-desktop-portal. я вам и отвечать начал потому, что я никакого Flutter никогда не пользовал - а ошибку именно эту вижу то и дело. Не удивлюсь, если GTK программно не сообщает об ошибке, а возвращает значение по умолчанию. На GTK писать - себя не уважать.


          1. Octabun
            22.05.2024 12:21

            На GTK писать - себя не уважать.

            Принято к сведению, спасибо. Я постепенно склонялся к тому же...


            1. MountainGoat
              22.05.2024 12:21

              Ну смотрите: разрабы GTK много раз говорили, что их не волнует, как GTK работает за пределами проекта Gnome. То есть для сторонних разработчиков GTK - это по сути неподдерживаемая библиотека. Писать софт, особенно новый, на неподдерживаемом UI тулките - это себя не уважать.


              1. 9241304
                22.05.2024 12:21

                А что порекомендуете для написания кастомного кроссплатформенного инсталлера с gui с небольшим оверхедом без зависимостей?


                1. MountainGoat
                  22.05.2024 12:21

                  Порекомендую статическую линковку. Или жмотную упаковку. В любом случае, "всё своё ношу с собой" - это на десктопе самый разумный подход. Разделяемые библиотеки на практике не оправдали себя, всё равно на Винде каждое приложение таскает с собой свой набор, а на Линуксе либо то же самое, либо требуется сборка под конкретный релиз конкретного дистрибутива.

                  Так что:

                  • С++ + Qt + статическая сборка

                  • Python + Qt или что попроще + PyInstaller

                  • Rust + EGUI. А сборка там всегда статическая

                  Попроще - это ImGUI и порты его на все языки. А вообще, что ж за инсталлер у вас такой, что InnoSetup не подходит?

                  А если цель - сделать выпендрёжно-красиво, то есть НЕ нативно, и есть фронтэндщики, то не брезгуйте подходом интерфейса на HTML. Electron дал этой концепции дурную славу, но это целиком вина реализации, а не принципа. Sciter, PyWebView и Tauri все работают не хуже Qt и GTK если писать аккуратный HTML.


                  1. 9241304
                    22.05.2024 12:21

                    Рассчитывал как-то на более серьёзный ответ... InnoSetup, InstallShield, как и всякие NullSoft не подходили никогда, проще и правильнее (даже сейчас) взять WIX.

                    Статическая линковка сама собой подразумевается, как и компилятор gcc

                    Ваши рассуждения о текущем положении дел тоже неправильные, есть Qt Installer (тоже не подходит ввиду завёрнутой логики), который сделает всё стандартное красиво, и ни от чего не зависит.

                    1. Дикий размер, отсутствие готовых бинарников.

                    2. Ещё и разборки с питоном сверху...

                    3. У рустика на винде зависимость от рантайма msvc, декларируемое переключение на mingw не заработало.

                    Цель: всего лишь получить кастомный инсталлер с минимальным оверхедом. И выходит, единственный подходящий вариант для таких целей - это GTK.


                    1. MountainGoat
                      22.05.2024 12:21

                      Приложение на Qt5 в два окошка на Python с PyInstaller весит в релизе 15 мегабайт. Мне норм.

                      Красивые 20мегабайтные инсталляторы всяких приложений не переносимы, они через WinAPI открывают окно, потом через Sciter рисуют в него свои красоты.


                      1. 9241304
                        22.05.2024 12:21

                        Ну вот и я об этом же. Проще уже тогда даже голанг взять. Всё будет сразу из коробки, и всего 9 МБ.


          1. MountainGoat
            22.05.2024 12:21

            Ну например. Я не знаю, в чём заключается именно эта ошибка, но, зная, чем занимается xdg-desktop-portal, могу придумать вот такой сценарий. Flutter хочет, чтобы юзер выбрал папку. Flutter говорит GTK открыть диалог выбора папки. GTK командует порталу открыть доступ к списку допустимых зон сохранения неструктурированной пользовательской информации, потому что GTK лучше всех знает, как у них что должно называться. Портал отвечает: вы там ужратые что ли? в стандарте нет такого." GTK пишет ошибку в strerr, а в Flutter отвечает: юзер выбрал $HOME/Documents. Flutter пытается открыть в ней файл iostream-ом, получает отлуп и закрывается.

            Если xdg-portal-desktop ещё можно обвинить в том, что они не подстраиваются под вечно меняющиеся хотелки GTK (хотя, скорее всего, xdg-portal просто старой версии стоит), то что здесь Flutter вообще может сделать? Парсить stderr?


            1. Octabun
              22.05.2024 12:21

              Это точно не так. Это же счётчиковый вариант Hello World, никто никаких папок не открывает.

              И да, если иначе не получается - парсить stderr. Месячишко попарсят - может поймут что подход "мама, смотри, на этой машине заработало!" не без изъянов.