Впервые я погрузился в мир разработки мобильных приложений около десяти лет назад. Я только что купил свой первый iPhone (3GS), и мне было любопытно сделать что-нибудь для этого чудесного маленького устройства (статья Георга фон дер Ховена публикуется в переводе – прим. ред.).
Сначала я написал стандартное веб-приложение с использованием библиотеки jQTouch и завернул его в контейнер PhoneGap для iOS. После запуска мой проект очень быстро попал в список рекомендованных приложений Apple в медицинской категории. Кажется, мне удалось сделать что-то хорошее.
Спустя несколько лет я переписал его как нативное мобильное приложение на Swift, а потом решил расширять охват и портировать проект на Flutter. Сейчас я расскажу, что из этого получилось.

Flutter: Святой Грааль для кросс-платформенных приложений?
Когда я только принял решение наконец создать Android-версию проекта, встал логичный вопрос – как это сделать. Писать нативное приложение или использовать кросс-платформенные решения? Ionic c React'ом или Vue? Или, может быть, новый модный Flutter вокруг которого сейчас много хайпа?
Поразительно, но сначала все шло очень хорошо. Я ничего не знал о Dart или принципах проектирования пользовательского интерфейса Flutter (пришедших из iOS Swift и XCode Interface Designer), но почти за одну неделю смог запустить проект на Android и iOS.
Когда дело дошло до тестирования, я столкнулся с очень странным поведением. Во время загрузки главы электронной книги отображается спиннер. Как только данные загружены и визуализированы, я заменяю спиннер на WebView. Это очень просто, и в 99% случаев все было нормально. Но иногда все зависало на спиннере. Очевидно, это не то поведение, которое вы ожидаете от приложения для чрезвычайных ситуаций.
Около дня или двух мне потребовалось, чтобы найти проблему. Ошибка возникала в модуле Flutter HTTPServer, который крашился на iOS, если пользователь ненадолго переключался на другое приложение, а затем возвращался к книге. Я отправил подробный отчет о баге, но в ближайшее время исправлений не будет.
Так оставлять было нельзя, поэтому я начал искать альтернативные подходы. Я решил отказаться от запросов через HTTPServer, при первом запуске копировать содержимое книги в каталог документов и открывать HTML прямо в WebView используя протокол file://.
После нескольких тестов и рефакторинга это решение казалось вполне жизнеспособным. До тех пор, пока некоторые ссылки в книге не стали ломаться на физическом устройстве iOS. При этом на Android и в эмуляторе iOS все работало нормально. Оказывается, я нашел еще один баг – в этот раз в пакете Flutter WebView. Я отправил отчет, который быстро был подтвержден. Однако обе ошибки все еще не исправлены (по состоянию на февраль 2021 года).

Ад зависимостей
Модули HTTPServer и WebView – это две самые важные зависимости моего проекта. Без одного или другого мое приложение просто не будет работать. После некоторого опыта работы с iOS и CocoaPods я смотрю на каждую зависимость как на технический долг. Когда вы заимствуете чей-то код и полагаетесь на него, возможно, вам однажды придется заплатить за это.
Я был крайне удивлен, что эти модули получают так мало любви и внимания от разработчиков Flutter. Вероятно, нынешняя команда Google недостаточно велика, чтобы поддерживать и развивать этот проект (8200+ незакрытых ишьюс на Github), либо их приоритеты больше его не включают.
Учитывая эти соображения, давайте взглянем на зависимости моего приложения Flutter и нативной версии проекта на Swift.
Нативное iOS приложение (Swift)
- AEXML – для анализа XHTML-файлов. Собственный iOS SDK не предоставляет DOM-парсер.
- FontAwesome.swift – позволяет использовать иконки FontAwesome.
Версия на Flutter
- cupertino_icons
- HTTP
- provider
- shared_preferences
- font_awesome_flutter
- xml2json
- path
- path_provider
- mime
- flutter_web_browser
- webview_flutter
- url_launcher
- geolocator
- geocoding
- map_launcher
- wakelock
- device_info
- package_info
- scrollable_positioned_list
- in_app_review
- share
Ничего себе! Для чего мне нужно так много пакетов?
Так как мой проект – это не просто электронная книга, я добавил в него некоторые дополнительные фичи и сервисы, например:
- онлайн-поиск с использованием стороннего API;
- отображение информации о текущем местоположении пользователя с использованием геолокации и обратного геокодирования для помощи аварийным службам;
- быстрый набор экстренных номеров.
Для каждой фичи требуется взаимодействие с нативным SDK платформы: геолокацией, геокодированием или выполнением вызовов. Также требуется предотвращать уход в спящий режим, запрашивать у пользователя оценку, открывать карту, делиться контентом и делать другие вещи, которые делают все приличные приложения.
Таким образом, ваше приложение Flutter зависит от бесчисленных внешних библиотек, которые обеспечивают функциональность нативных приложений. И вы не знаете, кто и как их разрабатывает, какие у них планы, ограничения и мотивация. Каждая из них увеличивает технический долг вашего приложения.

Кроссплатформенность добавляет сложности
Если вы хотите свести технический долг к минимуму, придется написать 100% кода вашего приложения самостоятельно и использовать только нативные SDK для доступа к возможностям устройства. Конечно это практически невозможно. Поэтому, по крайней мере, тщательно выбирайте сторонние библиотеки, которые вы добавляете к вашему техническому долгу.
К счастью, моих навыков было достаточно, чтобы быстро найти эту ошибку, пофиксить ее и даже отправить патч владельцу репозитория. Но я смог это сделать только потому, что библиотека была написана на том же языке, что и мое приложение – на языке, который я хорошо знаю.
Если сторонняя библиотека написала на знакомом вам языке, вы вполне можете жить с этим долгом. Но каждое кросс-платформенное решение добавляет вашему приложению несколько уровней сложности и точек возможного сбоя.
В каждом пакете Flutter может встретиться баг в коде Dart, или в коде Swift/Objective-C, или в коде Java/Kotlin. А то и в нескольких частях сразу. Его может сломать любое обновление Flutter, Dart, iOS или Android – а вместе с ним сломается и ваше приложение на одной или всех платформах. Если вы не владеет всеми тремя языками и всеми поддерживаемыми платформами, то, вероятно, не захотите искать и устранять проблемы самостоятельно.
Даже если мне удастся найти баг в iOS-части плагина Flutter WebView, я не разбираюсь в Objective-C и не хочу тратить время на бесплодные попытки исправить его. По моему мнению это должно просто работать, если оно не находится в состоянии альфа- или бета-тестирования.

На кого вы хотите положиться?
Дополнительная сложность, которую привносит в проект Flutter, не была бы столь ощутимой и серьезной, если бы за ним стояла сильная организация, которая чувствует ответственность за обеспечение стабильной работы и взаимодействия Dart с нативными функциями SDK.
Все, что вам реально нужно от Flutter, – это написать свое приложение на Dart и развернуть его на iOS и Android. И вы верите, что кросс-платформенное решение позволит вам это сделать, сэкономив время и деньги по сравнению с альтернативными решениями.
Теоретически Flutter может это сделать, но лишь теоретически. Его способность выполнять заявленные обещания все еще оставляет желать лучшего, особенно на iOS. Может быть это связано с уклоном в сторону Android или создателям продукта просто не хватает опыта, но как кросс-платформенная среда разработки Flutter пока проваливается. Если кросс-платформенное решение не может надежно обеспечивать работу с часто используемыми функциями на всех поддерживаемых платформах, оно теряет свои преимущества и лояльность разработчиков.
Я не уверен, что Google сможет сделать Flutter таким же удобным, как нативная разработка. Если они действительно стремятся к этому, то придется вложить больше усилий и денег в проект.
Может быть мне просто не повезло, и моими основными зависимостями оказались единственные два неисправных пакета из экосистемы Flutter. Читая открытые ишьюс на GitHub, я почему-то в этом сомневаюсь. Глядя на накопленный моим приложением с Flutter технический долг, я желаю удачи своим коллегам-разработчикам, которые уже запрыгнули в этот поезд.
Мне сейчас интересно, сможет ли Ionic справиться с моими задачами лучше. Судя по всему, они сталкиваются с очень похожими проблемами, но пока я не собираюсь переписывать свое приложение еще раз.
Комментарии
Автор, нечего на зеркало пенять, коли рожа крива. Описываемый проект книги на стероидах - это дано не изюминка и если ты не шаришь как его реализовать - флаттер тут не причем. Всем, кто читает статью - не читайте этот бред. Флаттер отличный инструмент, позволяющий реализовать проекты на порядок сложнее. Flutter - отличный инструмент! я бы сказал супер фреймворк, которого столько лет ждали. Появись он в 2010, мир стал бы другим. Но всегда находятся такие бараны как этот автор, которых 10 летний опыт программирования не прокачивает, а просрочивает.
Командой за год напилили более 5 проектов на flutter в т.ч flutter for web, в проде полет отличные, в основном команда пришла из мира андройд. Flutter очень продакшен реди решение
А можно пожалуйста примеры под веб? Я под Flutter пишу на iOS/Android с момента релиза, очень нравится. А вот с web пока опасаюсь.
Flutter имеет некоторую особенность. В нем все устроено немного не так, как ты привыкаешь за 10 лет разработки на других технологиях. Первое время у всех, кто на него приходит начинает бомбить от непонимания "почему так?". И вот это тот момент, с которого и начинается реальная разработка на флаттере. Ты либо начинаешь психовать от собственной криворукости (как автор этой статьи, который зачем-то сделал проект на вебвью, а не на флаттере, и при этом катит бочку на флаттер), либо тебе начинает нравиться, как в моем случае. Уже 3 года разрабатываю приложения на флаттере и просто влюбился в эту технологию. Разработал уже 9 полноценных проектов, последние 3 из которых это энтерпрайз. Со многими проблемами описанными в этой чернухе сталкивался, и могу утверждать, что у них всегда есть довольно простое решение. Если проект живой, то часто бывает достаточно написать автору / сделать пулл реквест с фиксом. Если не живой, сделать либо форк либо вообще скачать себе локально в проект, исправить баг и радоваться жизни. Есть еще вариант найти аналог, в большинстве случаев они есть. Все эти способы я использовал и подобные проблемы благополучно решались в 100% случаев. Об авторе статьи могу предположить, что разработка - это просто не его, и пофиг какой опыт. Много лет человек занимается не своим делом, так бывает
Очень давно занимался программированием, всем по немного, а тут мне понадобился небольшой простенький web-клиент, взглянув на технологии, обратил внимание на flutter. Столько лет прошло, казалось для конструирования интерфейса web, да еще от google, должен был сделан нормальный удобный инструмент, но нет, через одно место. Вместо того, чтобы накидать интерфейс, прописать проперти и события, мне нужно на простых вещах заниматься изучением корявостей организации этого конструктора, с, мягко говоря, странной структурой. Да в том же CBuilder все было решено, что выдумывать эти извращения? Полунужные Key (аналог Tag контролов?), которые теряют связь с положением во внутреннем дереве, return виджета от контекста - google знает толк в извращениях. Одна мадам целой простыней на habr объясняла механизм потери связи.
Дарт - язык как язык, нормальный, мне приятен. Есть, конечно, непонятно зачем, value!, вместо !value, но до лампочки. Flutter, API с оптимизацией), дерево виджетов, как идея - отлично, но сам конструктор - редкое г. И подтверждение этому, что сами разработчики этого нарисовали несколько убогих демо, примеров. Не одного нормального, полноценного интерфейса. Потому что это неудобно и сложно в этом Flutter, я их прекрасно понимаю. Первая сборка под web - 30 сек и даже на простом чувствуется вялость отрисовки. Если намутить что-то сложное, то на вид он тормознет не по-детски. Самих виджетов - кот наплакал. Возьмем тот же OpenUI5, туча виджетов на все случаи жизни, где нужно, заточены на обмен с сервером, примеры, туча нарисованных сложных интерфейсов, но js (. Как все было на google: Пришел к руководству кто-то из своих с идеей: новый язык - замена js на удобоваримое, кросплатформенность, один язык для всего, трансляция в web js. Руководство - отлично, вот финансирование, делайте! Как дело дошло до UI, то js как-будто криво обернули в Dart. Руководство слышало характеристики, им же не рисовать интерфейсы. Если бы нормально реализовали конструктор и организацию интерфейсов, а тут еще и с рендерингом в отрисовку или html, то население побросало все vue, реакты, ангуляры и рисовало все приятным Dart, но, похоже, пока нет.
Зачем для простенького web клиента брать flutter? А если взяли чего ругаетесь на инструмент который не понимаете и который за пару дней не изучить. Если Вы не знаете чем отличается value! от !value, то тогда понятно что Вы просто не разобрались не то что с Flutter, а даже с Dart!
Flutter web вышел в релиз совсем недавно, когда был еще в бетта версии были баги, но сейчас их на много меньше с каждой новой версией. Во Flutter dart компилируется в js и использует в web не html, а canvas. Так это отличный инструмент на нем можно сделать все что хочешь или почти все)
Я не утверждал, что разобрался в dart и flutter, а отметил, с чем сразу столкнулся и что мне не понравилось. Да, в Dart value! - другое значение, просто рассмотрел его как аналогию С. Но на остальное ничего не ответили.
Повторю еще раз, мне не понравилось что в конструктор интерфейса притянуты проблемы и особенности реализации, которые не имеют отношения к созданию интерфейса. И это выглядит не очень после стольких лет от гиганта. А проблемы из-за дублирования возни с деревом, только на другом языке, но уже с api flutter.
На счет отрисовки canvas из скомпилированного в js: Благодаря явлению миру wasm, наличия api для web и через библиотеки к графическим движкам развивается тема интерфейсов для web на любом языке, как через api браузера, так и напрямую (html и пр. давай, до свиданья) Т.е. для web, пишем на С++ и др. языках с одной библиотекой, снизу webgl и ввод, компилим в wasm, запускаем в браузере.
С одного костыля пересел на другой, я вижу это так. Коли уже мигрируете на flutter, так сделайте это без веб вью. На кой чёрт он вам сдался? Это дичайший костыль в новой обёртке. Автор ты ...
Читал и еле сдерживал слезу. Разработчик приложений с опытом в 10 лет делает свой проект через webview...
А что не так? вполне очевидное решение если нужно отображать контент со сложным форматированием, у него там какая-то книжка и это вероятно страницы html
тут даже не знаешь, что сказать - только начал смотреть в сторону flutter и тут на тебе такие аргументы мб появятся еще отзывы от людей которые пишут на нем, чтоб холивар развести) и понял на самом ли деле он так плох за статью спасибо
Либо автор стати имел слишком завышенные ожидания от Flutter (как будто Flutter это не разработка с её типичными проблемами, а прогулка по цветочной лужайке), либо это целенаправленный вброс. Большинство доводов высосаны из пальца. Баги в пакетах, в т.ч webview? Это вполне нормально для развивающейся платформы. В iOS большинство вещей обкатаны годами, в то время как тот же webview относительно недавно вошёл в первый релиз. Много зависимостей в проекте? Я думаю автор не видел web-разработку на React/Node/Vue. Там зависимостей может быть в разы больше, чем приведено в примере. В целом Flutter находит компромиссы в этом вопросе, вынося только опциональные вещи в отдельные пакеты, тем самым не делая фреймворк раздутым. В том же андроиде аналогичный принцип применяеся в AndroidX библиотеках. Аналогично довод что кроссплатформенность добавляет сложность очевиден. Ещё нет такого фреймворка, который был бы таким же простым, как нативный) В любом случае такой фреймворк предполагает взаимодействие с нативным API и кодом, если нет готовых решений в виде пакетов, или же в пакете присутствует баг.