Про Flutter: как бекендер в мобильную кроссплатформу лез
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 подходит идеально: будь то интернет-магазины, витрины данных, корпоративные приложения, на которые тратить время групп нативной разработки — непростительная роскошь. Ребята могут заниматься в это время более сложными задачами, которые у них получаются просто прекрасно. Но надо всегда помнить, что никакая кроссплатформа не сможет превзойти нативные приложения: кроссплатформа — это всегда компромисс.