Flutter. Плюсы и минусы



    В первую очередь расскажем немного о том, что же такое Flutter. Это фреймворк для создания мобильных приложений от компании Google. Он является кроссплатформенным и позволяет компилировать созданный проект под 3 операционные системы:
    • Android
    • iOS
    • Fuchsia

    Причем для последней ОС – Fuchsia – это пока единственный способ создать приложение.
    Flutter на протяжении долгого времени, с 2015 года, был представлен только в альфа и бета версиях. Релиз первой стабильной версии состоялся 4 декабря 2018 года.


    Flutter активно продвигается Google, постепенно набирает популярность и, скорее всего, в дальнейшем будет теснить другие, используемые сейчас средства кроссплатформенной разработки (React Native, Xamarin), особенно при условии широкого распространения Fuchsia. С учетом того, что Google позиционирует данную операционную систему как замену Android, рано или поздно Flutter вытеснит нативную разработку под Android. Поэтому перспективность и активное развитие – основные плюсы Flutter.


    + Перспективность и активное развитие


    Давайте разберемся, как это работает.


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


    Одновременно в нативной части приложения создается один-единственный экран, где подгружается виртуальная машина Dart, которая и выполняет Flutter.


    Заметим, что отсюда следует один из минусов Flutter:


    — Конечный установочный пакет больше, так как в него добавляется виртуальная машина Dart.


    Таким образом, есть файлы Flutter и есть виртуальные машины, которые добавляются в зависимости от того, что компилируется – iOS или Android.


    В составе виртуальной машины есть собственный графический движок, он рисует интерфейс приложения со всеми переходами между экранами, диалогами, фрагментами и т.д. В этом разработка под Flutter значительно отличается от разработки с Xamarin и React Native, которые используют реальные Android и iOS компоненты. В случае с ними невозможно использовать специфические для платформы компоненты (если такая необходимость есть, приходится создавать два варианта UI). С Flutter при выборе дизайна достаточно ориентироваться на одну платформу (например, Android). При сборке проекта под iOS вы увидите стандартный Android интерфейс. Это будет выглядеть немного странно и неожиданно, но вполне работоспособно (впоследствии интерфейс можно доработать).


    + Собственный графический движок (нет необходимости делать интерфейс отдельно для Android и iOS)


    Теперь о впечатлениях.


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


    Первое, что бросается в глаза – это способ создания экранов, который значительно отличается от используемых на Android и iOS. В Android разделена логика и интерфейс: логика задается кодом, а интерфейс – версткой в xml. На Flutter все это задается с помощью кода. Хотя здесь для интерфейса используется особый стиль – элементы интерфейса создаются вложенными друг в друга. Это немного похоже на верстку, очень похожий способ действует в React Native. При этом отсутствует возможность прямого доступа к элементам. Чтобы что-то изменить на экране, нужно либо обновить весь экран, либо воспользоваться специальными контроллерами, заблаговременно добавленными к виджету во время его создания.


    — Интерфейс создается с помощью кода, из-за чего грань между логикой и дизайном гораздо тоньше.


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


    + Интерфейс легко разбивается на отдельные модули


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


    Сделаем три вкладки:


    1) Первая – с текстом и ползунками для настройки размера и цвета текста
    2) На вторую добавим загружаемую картинку (с индикатором прогресса)
    3) На третьей поместим пример списка




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

    Теперь рассмотрим исходный код, который реализует такую верстку:


    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
     // This widget is the root of your application.
     @override
     Widget build(BuildContext context) {
       return MaterialApp(
         title: 'Flutter Demo',
         theme: ThemeData(
           primarySwatch: Colors.blue,
         ),
         home: MyHomePage(title: 'Home Page'),
       );
     }
    }
    
    class MyHomePage extends StatefulWidget {
     MyHomePage({Key key, this.title}) : super(key: key);
    
     final String title;
    
     @override
     _MyHomePageState createState() => _MyHomePageState();
    }

    Данный фрагмент кода является стандартным для практически любого Flutter приложения (он создается вместе с проектом).


    MyApp – это класс самого приложения, в котором при создании MaterialApp описываются общие параметры: название приложения, шрифты, цвета и стили. Также здесь указывается основной экран приложения (для нас это MyHomePage).


    Сделаем важное замечание: во Flutter виджеты разделяются на два типа:


    1) StatefulWidget
    2) StatelessWidget


    Для описания StatefulWidget требуется два класса: класс самого виджета и класс его состояния (в котором и будет происходить основная работа).


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


    Теперь рассмотрим _MyHomePageState:


    class _MyHomePageState extends State<MyHomePage> {
     int _currentIndex = 0;
     double _size = 14;
     double _r = 0;
     double _g = 0;
     double _b = 0;
    
     @override
     Widget build(BuildContext context) {
       return Scaffold(
           appBar: AppBar(
             title: Text(widget.title),
           ),
           body: <Widget>[

    Для простоты восприятия красным цветом помечена вкладка с текстом, зеленым – вкладка с картинкой, синим – вкладка со списком, а желтым – навигационное меню. Как можно заметить, интерфейс описывается как множество вложенных друг в друга виджетов (и их массивов):










    Используемые функции:
     void _onTapped(int index) {
       setState(() {
         _currentIndex = index;
       });
     }
    
     void _setTextStyle(
         {double size = -1, double r = -1, double g = -1, double b = -1}) {
       setState(() {
         if (size > 0) {
           _size = size;
         }
         if (r > 0) {
           _r = r;
         }
         if (g > 0) {
           _g = g;
         }
         if (b > 0) {
           _b = b;
         }
       });
     }
    }

    Рассмотрим их немного поподробнее:


    onTapped – функция, вызываемая при переключении вкладки в нижнем меню. В ней вызывается специальная функция setState, которая позволяет обновить текущий виджет с новыми данными (а мы обновили переменную _currentIndex).


    Посмотрим, где она применяется:


    body: <Widget>[
            текст
            картинка
            список
            ][_currentIndex]

    Здесь мы имеем дело с массивом, откуда с помощью _currentIndex выбирается один из вариантов разметки экрана, и он подставляется как одна из вкладок.


    Далее идет функция _setTextStyle. Она имеет весьма необычное объявление для C-подобных языков.


    void _setTextStyle({double size = -1, double r = -1,
                           double g = -1,double b = -1})

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


    Так как каждый аргумент именован, то мы можем брать их в произвольном порядке. Например:


    _setTextStyle(size: 24, b: 255)

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


    Первая вкладка:


    class TextWidget extends StatefulWidget {
     @override
     _TextWidgetState createState() => _TextWidgetState();
    }
    
    class _TextWidgetState extends State<TextWidget> {
     double _size = 14;
     double _r = 0;
     double _g = 0;
     double _b = 0;
    
     @override
     Widget build(BuildContext context) {
       return Column(
         children: <Widget>[
           Text("Example String",
               style: TextStyle(
                   fontSize: _size,
                   color: Color.fromRGBO(_r.toInt(), _g.toInt(), _b.toInt(), 1))),
           Container(constraints: BoxConstraints.expand(height: 32.0)),
           Slider(
               label: "${_size.toInt()} sp",
               value: _size,
               min: 10,
               max: 48,
               divisions: 38,
               activeColor: Colors.black,
               inactiveColor: Colors.grey,
               onChanged: (val) => _setTextStyle(size: val)),
           Slider(
             label: _r.toInt().toString(),
             value: _r,
             min: 0,
             max: 255,
             divisions: 255,
             activeColor: Colors.red,
             inactiveColor: Colors.grey,
             onChanged: (val) => _setTextStyle(r: val),
           ),
           Slider(
             label: _g.toInt().toString(),
             value: _g,
             min: 0,
             max: 255,
             divisions: 255,
             activeColor: Colors.green,
             inactiveColor: Colors.grey,
             onChanged: (val) => _setTextStyle(g: val),
           ),
           Slider(
             label: _b.toInt().toString(),
             value: _b,
             min: 0,
             max: 255,
             divisions: 256,
             activeColor: Colors.blue,
             inactiveColor: Colors.grey,
             onChanged: (val) => _setTextStyle(b: val),
           ),
         ],
       );
     }
    }

    Так как виджет необходимо обновить (метод _setTextStyle), мы используем StatefulWidget.
    Для следующих двух вкладок нет необходимости в обновлении, поэтому будем использовать StatelessWidget.


    Вторая вкладка:


    class ImageWidget extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
       return Stack(
         children: <Widget>[
           Center(child: CircularProgressIndicator()),
           Center(
             child: FadeInImage.memoryNetwork(
               placeholder: kTransparentImage,
               image: 'https://picsum.photos/250?image=9',
             ),
           ),
         ],
       );
     }
    }

    Третья вкладка:


    class ListWidget extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
       return ListView.builder(
         itemCount: 25,
         itemBuilder: (BuildContext context, int index) {
           return Container(
             child: Text(
               'entry $index',
               style: TextStyle(color: Colors.white),
             ),
             margin: EdgeInsets.all(16.0),
             padding: EdgeInsets.all(16.0),
             decoration: BoxDecoration(
               color: Colors.blue,
               borderRadius: BorderRadius.all(
                 Radius.circular(16.0),
               ),
             ),
           );
         },
       );
     }
    }

    Измененный код состояния основного экрана:


    class _MyHomePageState extends State<MyHomePage> {
     int _currentIndex = 0;
    
     Widget build(BuildContext context) {
       return Scaffold(
           appBar: AppBar(
             title: Text(widget.title),
             actions: <Widget>[
               IconButton(icon: Icon(Icons.navigate_next), onPressed: next)
             ],
           ),
           body: <Widget>[
            TextWidget(),
            ImageWidget(),
            ListWidget(),
        ][_currentIndex],
           bottomNavigationBar: BottomNavigationBar(
             currentIndex: _currentIndex,
             onTap: _onTapped,
             items: [
               BottomNavigationBarItem(
                 icon: new Icon(Icons.text_format),
                 title: new Text('Text'),
               ),
               BottomNavigationBarItem(
                 icon: new Icon(Icons.image),
                 title: new Text('Image'),
               ),
               BottomNavigationBarItem(
                 icon: Icon(Icons.list),
                 title: Text('ListView'),
               )
             ],
           ));
     }

    Итак, мы легко разбили один большой экран на один маленький экран и три маленьких виджета. Можно заметить, что во Flutter экраны концептуально не отличаются от виджетов (точнее, виджеты берут на себя функции и активити, и фрагмента, и кастомных view). Эта особенность весьма удобна, когда в приложении нужен полноэкранный просмотр какого-либо элемента – для этого можно с минимальной доработкой использовать наши виджеты.


    И все же есть минимальные различия между виджетом, который используется как экран, и обычным виджетом. Корневым элементом для виджета экрана должен быть объект Scaffold (позволяет добавлять appBar, bottomNavigationBar, floatingActionButton, drawer и т.д.).


    На обычные виджеты данное ограничение не распространяется, так как с помощью метода build они встроятся в основной экран, где уже есть Scaffold.


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


    Также можно добавить SafeArea (чтобы обеспечить отступ для status bar). Получается следующее простое преобразование:


    От:


    @override
    Widget build(BuildContext context) {
      return [код];
    }

    К:


    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
        child: [код]
        ),
      );
    }
    

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


    Flutter недавно вышел в релиз, поэтому баги встречаются достаточно часто. Особенно это заметно при обновлении Flutter – некоторые библиотеки начинают работать с ошибками.


    — Нестабильность (совсем недавно вышел из beta)


    Очевидно, что при использовании нового фреймворка в вашем распоряжении гораздо меньше библиотек, чем при нативной разработке по Android/iOS. Однако, библиотек для Flutter все равно довольно много, и они продолжают появляться с большой скоростью. Так, например, многие библиотеки были добавлены во второй половине 2018 года, судя по всему, в рамках подготовки к первому стабильному релизу, а важнейшие библиотеки (Google Analytics, Firebase, Maps и т.д.) существовали и до этого.


    — Библиотек меньше, чем для нативной разработки
    + Важнейшие библиотеки уже есть, постоянно выходят новые


    Самое время подвести итоги! Давайте вспомним все плюсы и минусы, расположив элементы от самых существенных плюсов до самых существенных минусов:


    + Кроссплатформенность
    + Перспективность и активное развитие
    + Важнейшие библиотеки уже есть, постоянно выходят новые
    + Собственный графический движок
    + Интерфейс легко разбивается на отдельные модули


    — Конечный установочный пакет больше, так как в него добавляется виртуальная машина Dart
    — Интерфейс создается с помощью кода, из-за чего грань между логикой и дизайном гораздо тоньше
    — Библиотек (и информации) меньше, чем для нативной разработки
    — Нестабильность (совсем недавно вышел из beta)


    Спасибо за внимание!

    SimbirSoft
    90,04
    Лидер в разработке современных ИТ-решений на заказ
    Поделиться публикацией

    Комментарии 45

      0

      А где можно прочитать про то, как google позиционирует fuchsia?

        0
        Представители Google осторожны в высказываниях, и официальных планов по развитию Fuchsia пока нет. «Google смотрит на эти эксперименты с открытым кодом как на инвестиции в инновации», — например, так ответили журналистам Bloomberg. По данным других источников Bloomberg, однажды Fuchsia заменит Android, но это вряд ли произойдёт раньше, чем через пять лет.
          0
          я просто, например, читал, что google позиционирует fuchsia как os сугубо для loT устройств
        0
        Спасибо за статью, сам сейчас рассматриваю Flutter для коммерческой разработки. Вы его только смотрели, или попробовали в бою? Если да, хотелось бы послушать про реальный опыт.
          0
          Мы рады, что статья вам полезна! Да, мы пробовали Flutter на одном небольшом проекте.
            +1
            Тогда я готов завалить расспросами :)
            • Общее впечатление разработчиков — понравилось ли писать на Flutter? Подход-тулинг-язык?
            • Насколько удобно было писать (по сравнению с нативом)?
            • Насколько сильно приходилось if-ами прописывать разные виджеты для разных платформ?
            • С какими проблемами производительности-стабильности столкнулись?
            • Планируете ли использовать дальше на более крупных проекта?
              0
              1. Общее впечатление отличное. Как по мне, то порог входа достаточно низок, все интуитивно понятно, документация по самому фреймворку на достаточном уровне.
              2. Я лично до этого вообще не писал для моб, но со слов остальных членов команды Флаттер по удобности переплевывает натив.
              3. if нужны только если хочется отдельные дизайны для разных платформ. Если дизайн одинаковый, то кодовая база одна и никаких if.
              4. Скорее да.
              Как-то все слишком позитивно получилось, но нет, я не продвигаю Flutter если что:). Трудности были, но все они больше связаны с отстутствием опыта, периодической несовместимостью различных библиотек между собой, но это все есть и в других фреймворках
                +2
                Да, понравилось, особенно легкость, с которой интегрируется Flutter в AndroidStudio. Сам подход и язык тоже были признаны достаточно удобными, хотя и несколько непривычными после длительной нативной разработки. У Flutter отличается концепция верстки, но уже в течение первой недели разработки мы втянулись. В нашем случае мы переносили уже существующее приложение с Android на Flutter, оно выглядело идентично на Android и iOS. По производительности особых замечаний не было, по стабильности были вопросы, когда обновляли Flutter или какую-либо из сторонних библиотек (но это лечилось тщательной чисткой проекта). С крупными проектами – посмотрим, но сейчас у нас в работе еще один проект среднего масштаба на Flutter.
              0
              Попробовали Flutter на двух небольших проектах: один на хакатоне, второй коммерческий. Остались очень довольны выбором, т.к. в коммерческом проекте нужно было реализовать уникальный дизайн, который был бы одинаков на двух платформах и Flutter как раз в это умеет. К Dart быстро привыкаешь, библиотек уже хватает, hotreload is amasing ты мгновенно видешь все внесенные изменения с сохранением состояния, и прочие плюшки
            0
            Конечный установочный пакет больше, так как в него добавляется виртуальная машина Dart.

            Вы наверное хотели сказать не виртуальная машина а рантайм? Это очень разные вещи.
              0
              Реальная виртуальная машина там тоже есть, но добавляется только в debug сборку. А в release добавляется просто библиотека графического движка для отрисовки виджетов.
                +1
                — Конечный установочный пакет больше, так как в него добавляется виртуальная машина Dart.

                Но это в режиме debug, а когда собирается конечный продукт (release) в нем отсутствует «виртуальная машина» и…
                добавляется просто библиотека графического движка для отрисовки виджетов

                А также приложение весит всего 4-5(mb) Android и 2-3(mb) IOS, и ещё в конечном результате приложение собирается в native версию.

                Почему тогда это относиться к минусу?
                ВМ, для разработки это большой плюс.
                  0
                  Мы об этом уже писали в комментариях. Даже в release, по сравнению с Android, размер получается несколько больше. Хоть и не так критично, как в debug.
                    +1
                    У вас смысл потерялся, вы написали что в
                    — Конечный установочный пакет больше, так как в него добавляется виртуальная машина Dart.

                    На самом деле в release версии виртуальной машины Dart там нет!
              +1
              Вспоминаю электрон и не нахожу ответа на самый главный вопрос: как обстоят дела с потреблением памяти и ресурсов процессора?
                +1
                В этом отношении проблем не заметили.
                +1
                Спасибо за статью, можно вопрос «от чайника»? Вот и Вашей статье, и в других статьях по Flutter всегда подчеркивают, что исходный код Dart компилируется в нативное приложение. Для iOS понятно. А что есть «нативное» для Андроида? Это действительно исполняемый файл Линукса или все-таки байт-код для виртуальной машины Андроида? Если это исполняемый файл Линукса, то как реализована платформенная зависимость х86/х86_64/arm и есть ли возможность прицепить сторонние динамические библиотеки (*.so)? Как реализованы права доступа к аппаратным ресурсам? Если я запустил такое приложение из под root, у приложения автоматически полный доступ по всему? Я всегда считал, что виртуальная машина — это есть одновременно и сердце и главное преимущество Андроида, а тут выглядит как шаг назад обратно к машинному коду. Или я ошибаюсь?
                  0
                  Вопрос о прогрессивности Flutter вызвал у наших разработчиков оживленную дискуссию, поэтому, полагаем, на этот вопрос трудно ответить однозначно) Что касается исходного кода Dart, он компилируется в нативные библиотеки для ARM и x86 и подключается к Android проекту. Скорее всего, такой подход продиктован стремлением увеличить производительность и снизить зависимость от Android для возможного перехода на Fuchsia.
                    –1

                    Так там на выходе собирается apk-файл.

                      +1
                      В Android любые пользовательские приложения выполняются каждое в своей «песочнице», при этом неважно, скомпилировано ли приложение в платформенный машинный код или в платформонезависимый байткод типа Dalvik. Более того, со времен ART то, что вы называете «виртуальной машиной» практически отсутствует, потому что ART автоматически перекомпилирует байткод из APK в нативный платформенный код («исполняемый файл Линукса», если угодно) заранее после установки приложения либо во время первого запуска, а не занимается постоянной JIT компиляцией байткода во время его выполнения как Dalvik VM. Более того, никто не мешал и не мешает прицепить .so даже к байткоду в Dalvik VM — через JNI. Так что ваши представления о реализации механизмов защиты приложений в Android несколько… хм. Ну и Android NDK был с нами с первых версий Android и никуда пропадать не планирует, на его основе вполне себе пишутся и работают приложения в нативном коде под Android, я лично делаю это на Qt, вот сейчас и Flutter появился примерно с той же парадигмой. Это вовсе не «шаг назад», а скорее «шаг вперед», особенно в плане производительности.
                        +1
                        Спасибо, развернуто и понятно написали. Так уж получилось, что все свои приложения я писал на Джаве, Котлин никогда серьёзно не рассматривал, так как по сути это та же самая VM, только синтаксис птичий. Поэтому фраза «компилируется в нативный код» меня и заинтриговала. Вот и пытаюсь разобраться. И, вроде, действительно привлекательно выглядит, чтобы на эту технологию переходить. Я автор микро-Математики (https://github.com/mkulesh/microMathematics) и просто пытаюсь понять, стоит ли её портировать на Flutter и насколько это сложно. Явные плюсы — производительность и iOS, но трудозатраты большие, что пугает.
                          +1
                          Ну если вы хотите iOS, то придется по-любому ваш продукт на чем-то переписывать — либо на ObjC/Swift (но тогда вам придется параллельно поддерживать обе, мягко говоря, не пересекающиеся кодовые базы), либо на чем-то кроссплатформенном, второе, по-моему, предпочтительнее. Правда, лично я все больше с Qt/QML имею опыт, Flutter не пробовал. Кстати, забавно, раньше при виде фразы «cross-platform mobile toolkit» в статье модно было плеваться в комментариях в стиле «фи, не нативно» (в том смысле, что контролы в UI выглядят не «родными»). Но в последнее время эта тенденция как-то затихает, и «собственный графический движок» у таких тулкитов и «единообразие внешнего вида приложения на всех платформах» уже начинает постепенно выставляться как плюс.
                      0
                      Конечный установочный пакет больше, так как в него добавляется виртуальная машина Dart
                      опять, уже столько написано про это, вы пробовали собирать release версию, а не debug. В debug еще и тормозит бывает, а в release все летает.
                        0
                        Release тоже пробовали, это можно заметить на скриншотах. Но даже в release версию добавляется библиотека графического движка, из-за чего размер apk все равно больше (хоть и не так критично, как в debug).
                        0

                        А почему используется такое решение с навигацией, а не роутинг с поддержкой Back Button?


                        Navigator.push / pushNamed etc.
                          0
                          Этот фрагмент кода приведен в качестве примера. Мы решили не загромождать код объявлением routes.
                            0
                            По моему мнению роуты как раз и помогают легко разбивать на смысловые модули/страницы, что Вы выделяете, как плюс.

                            А приходилось ли Вам уже писать Native модули, и если да, то на какие задачи?
                            Или пока библиотек хватало с головой?
                            Спасибо за ответы
                              0
                              Была ситуация, когда нам нужно было использовать веб-сокеты. Сейчас для этого уже есть библиотека, но на тот момент ее не было, поэтому мы обратились к Android и iOS библиотекам для передачи событий между нативной частью приложения и Flutter.
                          +1

                          Чувствую заминусуют меня за этот коммент но… Вы пробовали использовать QT? Если да, то чем для вас он хуже флаттера? Мы, например, в команде попробовали флаттер и поняли, что на данном этапе это слишком сыро. Производительность заметно хуже, чем на QT, хотя и там и там отрисовка на том же вулкане. Плюс QT охватывает гораздо больше платформ, плюс это всё-таки C++, и с точки зрения оптимизации там все гораздо лучше и нет лишних виртуальных машин и тд. Да и библиотек под плюсы просто не пересчитать. При наличии хорошего дизайнера вполне можно получить красивое приложение и на кьюте. Ну и заодно я бы посмотрел, как вы будете подключать какую-нибудь библиотеку написанную на сях или плюсах к проекту на флаттере (например тот же linphone). В будущем может из флаттера и выйдет что-то интересное, но в данный момент для коммерческой разработки это слишком сыро и просто опасно использовать, особенно когда на кону серьезные деньги. имхо.


                          П.С. жду флаттер на базе го :) вот это было бы интересно :)

                            0
                            Нет, это другая ниша. Flutter позволяет писать кросс-платформенные приложения легко, но при этом не выжимая максимальную производительность. На QT процесс разработки усложняется, зато мы можем добиться большей производительности. Поэтому Flutter выгоднее использовать на небольших и средних проектах.
                              +1

                              На счёт сложности — а в чем сложность? Как по мне скакание вокруг сырости и багов гораздо сложнее, чем у более менее стабильного решения. Сложность в языке, то что там c++? Да, во флаттере есть готовые визуальные составляющие, которые смотрятся симпатично, но если нужно делать под конкретный дизайн, то там тоже начинается веселье. И как писал выше — использование любой сторонней библиотеки это боль и страдания. И не сказал бы, что это прям совсем другая ниша, скорее QT умеет в разы больше, но никто не заставляет всем этим пользоваться, можно пользоваться только теми инструментами которые нужны, а потом мучительно не переписывать на другой язык если проект вырастает. Да и комьюнити у кьюта огромно, есть форумы где можно найти и баги, и воркэраунды для их обхода, да и обновления выходят довольно часто. :)

                                +1
                                В Qt приложение зачастую можно написать так, что от C++ там будет только штампованный main.cpp из десятка строчек, инициализирующий декларативную машинерию и подгружающий локализацию, и все. Интерфейс при этом будет написан на QML, который вполне по силам освоить даже дизайнеру (он для этого и разработан), а бизнес-логика — на JS. При этом все будет летать, потому что QML-файлы инстанцируются в Qt'шные классы, у которых все внутренности (кроме пользовательских обработчиков событий, пожалуй, которые в данном случае будут на JS) написаны на C++. Причём даже все это можно ускорить ещё больше, перенеся момент парсинга/инстанцирования с момента подгрузки QML-файла на момент сборки приложения с помощью Qt Quick Compiler.
                                  0

                                  Кстати тоже отличный вариант :) Но в нашем случае приложение полностью на c++ без JS, архитектура viper, используется довольно много c++ библиотек (в том числе openssl), и отказались от qt quick. Тем не менее приложение работает очень шустро и выглядит вполне прилично, с анимашками и прочими финтифлюшками :) но согласен полностью, что можно пойти более простым путем и не усложнять себе жизнь, если того не требуют обстоятельства.

                                    0

                                    Подскажите новичку в мире мобилок. Нужно мне написать софт, наверное сначала под Андроид, потом и под iOS. Айфона и макбука нет. Лет 5 работал на c++, последние 10 лет больше c#. Немного смотрел Xamarin. Вот есть Flutter. С Qt немного работал. А ещё все эти react native и пр. Учить Java/Swift не считаю целесообразным. Что взять? У Qt есть эмулятор, или для iOS придется макбук+айфон покупать? Спасибо.

                                      0

                                      Ну, Qt существует, естественно, не в вакууме, как для сборки под Android ему нужны Android SDK и NDK, так и для сборки под iOS, соответственно, нужен Xcode. Эмуляторы есть в составе Xcode, но, чтобы его поставить, нужно устройство с MacOS. Говорят, на Хакинтоше Xcode нормально работает, но я лично не пробовал.

                              0
                              Касались ли вы вопроса использования C++ в приложении, написанном на Flutter?
                                0
                                Нет, пока мы пробовали на Flutter относительно лёгкие проекты малого и среднего размера. На них фреймворк показывал достаточную производительность.
                                0
                                Хотел бы задать вопрос касательно архитектуры Flutter-приложений.
                                Я разрабатываю некоторое приложение с Drawer, где в пределах одного Scaffold хочу обновлять body
                                Каждый body — отдельный класс. У меня имеется необходимость менять appBar в Scaffold из body после завершения какого-либо действия, например загрузки данных из сети. Я решил проблему следующим образом:
                                Создал абстрактный класс IPagedScaffold, в котором объявил метод updateTitle(String title) и реализовал его в State-классе своего Scaffold
                                Создал абстрактный класс MaterialFragment extends StatefullWidget, от которого будут наследоваться body, устанавливаемые в Scaffold
                                В классе MaterialFragment создал поле IPagesScaffold _scaffold и сделал для него геттер и сеттер. Сеттер я использовал в конструкторе State-класса моего Scaffold, вызывая в конструкторе метод body.setPagedScaffold(this);
                                В классах State я мог установить заголовок через widget.getPagedScaffold().updateTitle('Some title') и все было хорошо.
                                Но, заметив, что Android Studio подчеркивает MaterialFragment увидел сообщение, что классы Widget помечены как immutable и соответственно все поля должны быть объявлены как final. Это испортило все.

                                Получается, что я могу установить Scaffold только в конструкторе, однако в момент инициализации body, Scaffold может быть еще не создан, например в случае если я добавляю на экран сразу Scaffold вместе с body: new MyPagedScaffold(new MyMaterialScreen());

                                Попытался внутри класса State моего body сделать (Scaffold.of(context) as IPagedScaffold).updateTitle(«My title»), но получил сообщение об ошибке, что Scaffold не является экземпляром класса IPagedScaffold

                                Пока вижу два решения:
                                1) Оставить все как есть и не обращать внимания на предупреждение об иммутабельности Widget (мне видится это неправильным)
                                2) Создать класс-хранилище, который будет хранить в статичном поле экземпляр моего IPagedScaffold (вижу это решение очень грязным)

                                Скажите, пожалуйста, как можно решить мою проблему? Или я вообще изначально неправильно воспринимаю архитектуру приложений для Flutter?
                                  0
                                  Обычно на проектах мы используем архитектуру redux, где для решения подобной проблемы можно создать событие на обновление title bar определенного экрана.
                                  Или более простой вариант (без смены архитектуры):
                                  stackoverflow.com/questions/48481590/how-to-set-update-sate-of-statefulwidget-from-other-statefulwidget-in-flutter
                                  В State можно создавать обычные — не final — переменные и геттеры, сеттеры к ним (без предупреждений от Android Studio)
                                    0
                                    Да, то что в State можно создавать обычные поля я знаю. В варианте по ссылке в актуальном варианте решения предлагают передавать ссылку на State в конструктор виджета, откуда она записывается в собственное поле виджета _MyHomePageState parent:
                                    class Sub extends StatelessWidget {
                                    
                                      _MyHomePageState parent;
                                    
                                      Sub(this.parent);
                                    
                                      @override
                                      Widget build(BuildContext context) {
                                        return new InkResponse(
                                          child: new Container(
                                              margin: globalMargin,
                                              color: Colors.red,
                                              child: new Center(
                                                child: new Text(
                                                  "-",
                                                  style: textStyle,
                                                ),
                                              )),
                                          onTap: () {
                                            this.parent.setState(() {
                                              this.parent.number --;
                                            });
                                          },
                                        );
                                      }
                                    }
                                    

                                    стоит отметить, что в этом примере они также не указали _MyHomePageState parent как final, на что будет жаловаться Idea (что не будет при этом мешать коду корректно(?) работать). Если подразумевается, что виджет, получивший ссылку на _MyHomePageState является StatefulWidget виджетом, то эту ссылку можно будет передать в State и там уже делать с ней что заблагорассудится
                                    Моя проблема немного в другом: на момент создания как Parent-виджета так и Sub-виджета их State не определены, так как я в конструктор Parent-виджета пытаюсь передать Sub-виджет. Я пытался так сделать, чтобы один и тот-же класс MyScaffold можно было использовать как для фрагментов (замены содержимого Scaffold), так и для новых Route, просто создав экземпляр класса MyScaffold и передав ему в конструктор новый экземпляр вложенного виджета. Скорее всего мне нужно пересматривать архитектуру, но ничего внятного пока в голову не лезет
                                  +2
                                  Есть ли у кого-то опыт перехода с React Native на Flutter? Интересно услышать, что послужило причиной, с какими проблемами/ограничениями столкнулись и к какому выводу пришли.
                                    0
                                    Начал изучение Flutter с HelloWorld. Собрал проект, сделал релизную сборку, залил на iPhone и запустил — работает. Спустя неделю пытаюсь запустить залитую на девайс программу — получаю вылет сразу после запуска. Flutter выглядит уж совсем сырым.
                                      0
                                      При работе с релизной сборкой мы не сталкивались с такой проблемой.
                                      0
                                      рано или поздно Flutter вытеснит нативную разработку под Android

                                      Однозначно не «рано». Может когда-нибудь. но сейчас явных предпосылок к этому нет. Fuchsia еще в очень начальном состоянии и пока неясно что будет в итоге. А касательно самого Flutter — есть много готовых пакетов на pub.dartlang.org, которые мы можем подтягивать и использовать, работая только на Dart. Но, если глянуть их исходники, то там будет 1 враппер, написанный на дарте, а вся логика прописана на Java и Objective.
                                      Я вижу во Flutter очень мощный и интересный инструмент для создания UI. Но предпосылок для полного вытеснения нативки пока не вижу совершенно.

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                      Самое читаемое