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

Всем доброго дня. Меня зовут Сурен, и я разработчик.

Примерно последние лет 8 я занимаюсь разработкой ПО в компании Digital Design. Я уже писал статьи на Хабр, про Sitefinity, .NET и школу разработки.

Основное моё направление работы – .NET, и меня платформа устраивает как инструмент разработки распределенных систем, Backend для SPA/Mobile, но мне все время не хватало самого Mobile… В свое время пробовал Xamarin, но не зашло. Да, у него есть огромный плюс – разработчик пишет на том же языке и в той же среде, и можно переиспользовать код … Но так ли это важно? Особенно учитывая, что логика мобильного приложения сильно отличается от логики бека (серверной части). Да и в целом минусов и ограничений полно, для этого есть отдельные статьи на Хабр. Я здесь с другой целью.

Существует множество способов/технологий разработки мобильных приложений, кроссплатформенных и не очень. Но для меня как для backend разработчика на .NET все они были достаточно сложными и с высоким уровнем вхождения. Я думал, что более-менее знаю JavaScript, поскольку в web-разработке всегда приходится что-то исправлять и не всегда есть свободные «фронт-разработчики», а проекты, как известно, имеют свойство гореть. 

Когда я открыл код существующего приложения на React Native, то понял, что не знаю JavaScript =) Даже фронт, написанный на React, более понятен, чем мобилка на React Native (для меня). Помню, спросил у разработчика, владеющего обеими технологиями, можно ли перевести front, написанный на React, на React Native-приложение и сколько это займет времени. Он мне ответил: «Давай лучше перепишем на Flutter». Я тогда не был сведущ в современных тенденциях мобильной разработки и сначала подумал, что это очередной фреймворк на js. Через некоторое время наткнулся на статью о кроссплатформенной разработке в мире мобильных приложений, из которой узнал, что появилось что-то новое и имя ему – Flutter.

В чем удобство?

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

Интерфейс

Приложение на Flutter представляет собой single-activity|storyboard приложение, то есть приложение с одним экраном, на котором располагается окно отрисовки собственного 2d графического движка, способного рендерить с частотой до 120Hz. При этом минимизируется зависимость от платформы, и приложение без зависимостей от платформенных особенностей будет выглядеть одинаково на любой версии Android или iOS.

У приложения единый UI на всех платформах. Единая логика. Вы просто пишите приложение для одной платформы, а оно будет так же работать на другой. Если упрощать, то Flutter – это UI фреймворк, построенный на принципе “It`s all widgets”, что можно переиначить как «все, что вы видите – это виджеты». UI Flutter`а построен на виджетах, маленьких кирпичиках платформы, которые встроены друг в друга. У всех виджетов есть дети (дочерние виджеты), у каких-то виджетов (row, column, listView, ...) это массив, у каких-то один-единственный, который также может включать своих детей – по сути, дерево. Виджеты-родители являются оберткой для виджета-ребенка, к примеру:

Center располагает вложенный элемент по центру.

Column располагает элементы вертикально, в виде столбика.

Row – соответственно горизонтально.

Виджеты во Flutter можно поделить на 3 группы: стандартные общие виджеты, виджеты, реализующие гайдлайн дизайна Материал (Android style) и Cupertino widgets (iOS style).

У Flutter есть 2 базовых класса для создания своих виджетов, а именно:

StatelessWidget, не требующий изменяемого состояния, и StatefullWidget, имеющий изменяемое состояние. Отличаются они, по сути, тем, что первый рендерится целиком и, если вам надо поменять какой-то элемент в нем, то придется перестраивать виджет полностью извне. Второй же может отрисовывать конкретные изменения внутри себя без перерисовки всего виджета.

Еще один плюс дерева виджетов – это его схожесть с деревом фреймов в Figma, в которой проектируют интерфейсы UX, а также достаточно мощная система стилизации виджетов, позволяющая «переносить» дизайн из Figma в приложение, а не рисовать его с нуля.

HelloWorld на flutter

Это весь файл main.dart, который выведет “Hello world! “ по центру экрана устройства.

Про низкий порог вхождения

Dart — язык программирования, созданный Google. Он позиционируется как замена/альтернатива JavaScript.

Одна и задач разработчиков языка гласит: «Сделать язык похожим на существующие для упрощения обучения», и они справились на все 100%. Мне как .NET-чику не пришлось учить язык, чтобы писать на нем: посмотрел пару примеров, а дальше писал «по наитию», предполагая наличие того либо иного свойства, либо метода у различных объектов.

К примеру, способ пройти по всем заданиям и вытащить картинки для отправки на сервер, полученные с камеры, похож на методологический linq в C#:

Меняем Select на map, а SelectMany – на expand =)

Future помечаются асинхронные методы, как Task в C#, ключевое слово async идет не в начале метода, а перед его телом.

  Future _sendPhotos(Bypass bypass) async {
    var attaches = bypass.jobs
        .where((job) => job.photos.any((element) => element.id == null))
        .map((e) => JobFiles(
            e.id,
            e.photos
                .where((element) => element.id == null)
                .map((e) => File(e.localPath))
                .toList()))
        .toList();

    for (var i = 0; i < attaches.length; i++) {
      await _apiRepository.addPhotosToJobResult(
          attaches[i].jobId, attaches[i].files);
    }
  }

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

Также на Google Codelabs есть уйма уроков на все случаи жизни. У кого сложности с английским языком, есть альтернатива на русском (flutter.su). Там за 7 уроков вы освоите все необходимое для разработки приложения. Главное – помнить, что на официальном сайте информация обновляется быстрее, на сторонних ресурсах представленные примеры кода могут оказаться нерабочими.

Опыт

Теперь о нашем опыте. Приложение MVP я разработал в течении месяца, при том, что на старте знаний платформы или языка у меня не было. Задача была реализовать интерфейс, спроектированный нашими UX-дизайнерами, (около 5 экранов и состояний) и реализовать бизнес-процесс прохождения чек-листа (чек-листы/задания/блоки параметров). На текущий момент приложение из MVP переросло в полноценный проект, и релиз приложения внедрен у заказчика. О трудозатратах судить сложно, но что мы вынесли из нашего опыта, разработка на Flutter для обоих платформ составляет примерно ¾  от разработки 2-х нативных приложений (iOS и Android) с рисками ;-)

Но есть и ложка дегтя: приложение, которое писалось для iOS, спустя 4 месяца на Android не заработало, так как за время разработки ушел в небытие один из публичных репозиториев (привет, JCenter) =) и пришлось еще обновить gradle. Вообще чтобы с первого раза все запустилось на обеих платформах, при кроссплатформенной разработке все же нужно понимать, как на каждой платформе устроен менеджер пакетов, иметь обновленные инструменты. В конечном счете после манипуляций с пакетами и обновления всего и вся (1,5 дня) у нас все запустилось и сейчас работает без проблем. Но самое главное – мы не столкнулись с ситуацией, когда на одной платформе баги есть, а на другой нет, все манипуляции не затронули код проекта, только окружение.

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

Ограничения

На мой взгляд, если вы пишете приложение, активно использующее внутренние возможности платформы, будь то видео звонки, криптографическое шифрование туннеля ��ли дополненная реальность, то возможностей Flutter вам может не хватить. Тут на помощь придут каналы платформы (platform channels) – компонент, позволяющий из dart-кода вызывать нативный код на java/kotlin для Android и на objective-c/swift на iOS. Даже есть удобный пакет Pigeon, который позволяет по классу на dart`е генерировать код на обоих платформах. Тут есть очень большой минус: нужно либо владеть нативными языками для каждой из используемых платформ, либо привлекать нативных специалистов, что мы и сделали, когда писали пакет по поддержке криптографических алгоритмов.

Также Flutter не подойдет для game-dev, поскольку движок у него 2d и рассчитан в основном на рендер интерфейса, полноценных мобильных игр на нем не напишешь.

Вместо вывода

На мой взгляд, Google удалось сделать то, что долгое время не удавалось никому, так как благодаря Flutter в нише разработки приложений на iOS/Android появился достойный конкурент нативной разработке. Не лишенный недостатков, конечно, но имеющий все для их преодоления. Приложения получаются компактные и быстрые как в разработке, так и в работе. Это позволяет неплохо так сэкономить на этой самой разработке.

Есть целый пласт приложений, для которых Flutter подходит идеально: будь то интернет-магазины, витрины данных, корпоративные приложения, на которые тратить время групп нативной разработки – непростительная роскошь. Ребята могут заниматься в это время более сложными задачами, которые у них получаются просто прекрасно. Но надо всегда помнить, что никакая кроссплатформа не сможет превзойти нативные приложения: кроссплатформа – это всегда компромисс.