«Давайте уволим половину разработчиков»: кроссплатформенная мобильная разработка в 2019 году

Никому не хочется делать работу дважды, и индустрия давно ищет способ разрабатывать для iOS и Android одно приложение вместо двух. До сих пор ни одна попытка реализовать это не становилась триумфальной, но в последнее время заявляют о себе три новых. Чем они отличаются, и может ли у них получиться лучше?

«Давайте уволим половину разработчиков»: кроссплатформенная мобильная разработка в 2019 году

Когда у компании есть приложения для iOS и Android, многие задачи при их разработке оказываются идентичными. Неудивительно, что возникает ощущение «у нас две команды разработчиков делают одно и то же, давайте как-то из двух кодовых баз сделаем одну, будет проще и дешевле». И давно появлялись различные решения для кроссплатформенной разработки, от PhoneGap до Xamarin.

Однако не всё так просто. Помимо идентичных задач, есть и платформозависимые, когда подходы на iOS и Android ощутимо различаются: работа с UI, обращение к hardware-компонентам вроде камеры или сенсоров, и так далее. В итоге благие намерения «давайте из двух кодовых баз сделаем одну» нередко заканчивались тем, что баз становилось три (общая, которая используется обеими платформами, и две специализированные). На трёх разных языках. Компании обнаруживали, что результат противоположен ожиданиям, и разочаровывались.

В последние годы главным претендентом на успех был фреймворк React Native от Facebook, и определённую нишу он действительно сумел занять. Но повсеместного распространения всё же не получил, а без разочарований не обошлось: в прошлом году нашумел пост Airbnb, которые после двух лет использования React Native отказались от него и вернулись к раздельной нативной разработке.

Несмотря на это, продолжают появляться новые решения. Какие именно и что заставляет их создателей считать, что вот в этот раз получится?

Flutter

«Давайте уволим половину разработчиков»: кроссплатформенная мобильная разработка в 2019 году

Разработка этого фреймворка началась ещё четыре года назад, а в 2017-м можно было услышать о том, что с его помощью сделали приложение мюзикла Hamilton. Но тогда всё это было на стадии эксперимента, а в декабре Flutter дошёл до версии 1.0, и теперь интерес в сообществе разработчиков такой, что появился даже русскоязычный Flutter-подкаст — в общем, настало время присмотреться всерьёз.

Flutter создан Google, что может звучать неожиданно. Эта компания стремится, чтобы нативная разработка Android-приложений была как можно удобнее. Зачем та же самая компания вкладывает ресурсы в альтернативный способ разработки, позволяющий делать приложения ещё и для конкурирующей платформы? Что вообще происходит?

Отчасти причина в том, что эта история не только про мобильные платформы: в перспективе Google хочет позволить запускать Flutter-приложения «везде, где можно отрисовывать пиксели», и уже начата работа над поддержкой десктопа и веба. А когда (и если) выйдет ОС Fuchsia, зреющая сейчас где-то в недрах Google, Flutter может стать основным способом разработки для неё.

Но это всё будущее, а что есть здесь и сейчас? Возможность писать кроссплатформенные мобильные приложения на языке Dart. Основным преимуществом, помимо переиспользования кода, Google называет функцию Hot Reload: если при нативной разработке, внеся изменения в код, придётся подождать, прежде чем увидишь их в запущенном приложении, то здесь они срабатывают почти моментально.

Это должно упрощать и ускорять разработку. Но про ускорение говорили и в случае с React Native, и это не сделало его популярнее нативной разработки. А в чём отличия, способные заставить кого-то выбрать Flutter?

Например, в подходе к UI. React Native использует нативные элементы интерфейса: если вы добавляете в проект кнопку, то в iOS-варианте приложения появится стандартная iOS-кнопка, и аналогично с Android-вариантом. Flutter решительно отказывается от этого: он не вызывает стандартные элементы ОС, а говорит «весь экран — мой холст, что хочу, то и рисую» (это стало возможным благодаря применению графического движка Skia, который уже давно используется в Google Chrome). И предлагает нарисовать что-нибудь такое, не привязанное к визуальному языку ни одной из платформ:

«Давайте уволим половину разработчиков»: кроссплатформенная мобильная разработка в 2019 году

Но если вы хотите «чтобы пользователю было привычно», это тоже не проблема: во Flutter встроен свой набор готовых UI-элементов, имитирующих привычные iOS/Android-элементы.

Помимо подхода к UI, на руку Flutter играет как раз тот факт, что он создан владельцами Android. Например, в качестве основной среды Flutter-разработки Google предлагает использовать свою Android Studio, которую Android-разработчики уже отлично знают. При этом строгого требования «только Android Studio» нет, у Flutter есть поддержка и в Visual Studio Code.

Есть и проблемные стороны. Одна из них в выборе Dart. Во-первых, этот язык не используют ни в iOS, ни в Android. Во-вторых, его вообще мало где используют: если React Native помогало обилие JavaScript-разработчиков в мире, то опытного Dart-разработчика найти затруднительно. Но попробовавшие Dart дружно говорят, что освоить его после Java или другого ОО-языка несложно, так что принципиального барьера здесь нет.

Другая проблема — в репутации Google как компании, часто убивающей собственные проекты. Поэтому даже после релиза Flutter 1.0 у многих осталось настороженное отношение: «Что будет, если мы перепишем всё на Flutter, а потом Google его забросит?»

Ну и, наконец, Flutter не совершает чуда: хотя в случае с UI и избавились от привязки к платформе, в ряде других задач эта привязка остаётся. Так что полностью абстрагироваться от платформы не получится, при разработке по-прежнему потребуются знания и по iOS, и по Android. А в части случаев по-прежнему будут получаться три кодовые базы на трёх разных языках. В общем, помочь Flutter может, но ожидать «всё упростится ровно вдвое» не стоит.

Kotlin multiplatform

«Давайте уволим половину разработчиков»: кроссплатформенная мобильная разработка в 2019 году

Язык Kotlin уже стал стандартом в Android-разработке, приложения массово переходят с Java на него. Но Android дело не ограничивается: создавшая Kotlin компания JetBrains работает и над поддержкой самых разных платформ, и над удобством переиспользования Kotlin-кода между платформами. Один из предлагаемых вариантов такого переиспользования — как раз между Android и iOS.

У JetBrains есть важное отличие от многих других сторонников кроссплатформенности: там изначально не ставят целью «чтобы была одна полностью универсальная кодовая база». Пока кто-то стремится к этому идеалу и обжигает крылья, в этом случае сразу признают, что радикальный подход «всё общее» работает плохо, и даже не пытаются его воплотить.

Вместо этого предлагают переиспользовать только по-настоящему общую часть кода, где разработчики на разных платформах действительно пишут одно и то же. А всё различающееся по-прежнему писать нативно. И пока Flutter сосредоточен на полном объединении UI, здесь его, наоборот, никак не объединяют.

Грубо говоря, всё общее предлагают выделить в библиотеку на Kotlin, подходящую сразу для iOS и Android, а дальше обращаться к этой библиотеке с обеих сторон. Так что с Kotlin Multiplatform мобильный проект заведомо получается из трёх составляющих — общей и двух раздельных. И тут напрашивается возражение: «Подождите, мы оказывались недовольны, если из двух кодовых баз получалось три, а нам предлагают сразу же именно так и сделать. В чём тогда смысл вообще?»

Но здесь играет важную роль популярность Kotlin в Android-разработке. Если в других случаях «три кодовых базы» означает «на трёх разных языках», то здесь не требуется притаскивать в свой мобильный проект новый язык: зачастую он там и так уже есть. А в команде уже есть люди, умеющие на нём хорошо писать. Вот iOS-разработчикам придётся сталкиваться с новым для них языком, но им упрощает жизнь сходство Kotlin со Swift и интероперабельность со Swift/Objective-C. Любопытно, как это всё скажется на ролях в команде: границы платформ размываются и появляется «общая» часть, но она не одинаково близка обеим сторонам.

Выбрав подход «проект из трёх частей», JetBrains направили усилия на максимально бесшовное взаимодействие этих частей: идея совмещения «общего» и «платформозависимого» кода тут поддержана прямо на уровне языка. Когда одна и та же функция должна быть реализована по-разному на разных платформах, в «общем» коде её объявляют со специальным ключевым словом expect («такая функция в принципе есть, можно её вызывать»), а в «раздельном» с ключевым словом actual пишут две конкретные реализации этой функции. На скриншоте выше виден пример общего кода, функция platformName() действует по-разному в зависимости от того, на каком смартфоне она запущена.

Конечно, абсолютной бесшовности всё равно не достичь, и сложных вопросов на стыке разных миров остаётся много. Насколько успешно получится решить их у JetBrains — пока что открытый вопрос: если Flutter уже перешагнул через ключевую отметку «версия 1.0», то мультиплатформенные возможности Kotlin пока что снабжены значком «experimental», всё на более ранней стадии. И пока что нет примера большого приложения с Kotlin multiplatform (но можно посмотреть на код маленького).

Слово «экспериментальный» обычно означает, что тащить технологию в рабочий проект пока рано. Но также оно означает стадию, когда на неё можно ощутимо лично повлиять: многие важные решения всё ещё не отлиты в граните, и на них сказывается фидбек. Так что, если опробуете мультиплатформенность Kotlin применительно конкретно к своим задачам, столкнётесь с проблемой и сообщите о ней JetBrains — сейчас выше вероятность, что всё изменится в удобную вам сторону.

PWA

«Давайте уволим половину разработчиков»: кроссплатформенная мобильная разработка в 2019 году

В этом месте со стороны читателей могут полететь помидоры. Во-первых, если текст о разработке мобильных приложений, то при чём тут сайты? Во-вторых, как можно считать их «новым подходом» в 2019-м, если понятию PWA (Progressive Web Apps) далеко не один год, а Стив Джобс и вовсе предлагал использовать веб-приложения ещё при запуске первого айфона?

Действительно предлагал, но есть нюанс: веб-приложения в 2007-м и в 2019-м — это совсем не одно и то же. И буквально за последний год появились новые возможности, с которыми стоит ещё раз посмотреть на PWA и понять, не пора ли теперь считать их полноценными кроссплатформенными приложениями.

В чём исходная идея PWA? «Конечно, с сайтами удобно, что избегаешь всей этой тягомотины с дублированием iOS/Android, но нативные приложения в чём-то выигрывают. Например, они могут работать в офлайне и присылать уведомления, а их красивая иконка на домашнем экране и в App Store так и манит юзера тапнуть. Так давайте дадим сайтам все возможности приложений, и всё станет прекрасно!»

Процесс «дадим эти возможности» тогда действительно пошёл, но неторопливо. Хотя за идею PWA ратует Google, похоже, что внутри компании идёт холодная война между командами Chrome и Android: в Chrome хотят поскорее дать Android-пользователям все возможности PWA, но у Android-команды свои приоритеты вроде Instant Apps. А Apple вообще годами игнорировала это явление, не поддерживая возможности PWA на iOS, словно Джобс никогда не агитировал в пользу ничего подобного.

Но год назад тихо произошёл тектонический сдвиг: начиная с версии iOS 11.3, в Safari появилась поддержка ключевых PWA-технологий. При этом Apple настолько не высказывается об этом публично, что даже не сообщила об этих изменениях в списке нововведений iOS 11.3. И когда пользователь откроет ваш PWA-сайт, айфон не станет обращать его внимание «это веб-приложение можно добавить на домашний экран», как делает Android. Получается странная полуофициальная поддержка, при которой преимущества PWA могут пройти мимо заинтересованных людей. Но главное — лёд тронулся, теперь можно говорить о кроссплатформенности.

А вот другое событие, произошедшее меньше двух месяцев назад: в Chrome 72 для Android появилась поддержка Trusted Web Activity, и это шаг в направлении «публикация PWA в Google Play» (пока там всё непросто, но в будущем может стать проще). Зачем вообще веб-приложению публиковаться в магазине, если сайт и так доступен по ссылке? Потому что магазины остаются мощным источником аудитории, пользователи открывают их, когда хотят установить что-то.

Наконец, совсем свежая новость: поддержка PWA появилась в Chrome на macOS, и поскольку она уже была в Chrome на Windows и Linux, теперь десктопный сегмент охвачен целиком. Хотя это и не относится напрямую к мобильной разработке, для кого-то эта новость станет аргументом в пользу отказа от нативного подхода: «лучше сделаю сайт, который где угодно можно установить как программу, на любой телефон и любой компьютер».

В общем, сейчас создание PWA привлекательнее, чем когда-либо. Но при этом остаётся и миллион различных неудобств. Например, на iOS PWA-сервисы могут получать от камеры отдельные снимки, но не могут получать видеопоток (это портит жизнь, например, QR-сканерам). А на Android, если пользователь поменял телефон, система охотно восстановит установленные им на предыдущий нативные приложения — но не восстановит добавленные им на домашний экран PWA.

В итоге PWA технически уже можно назвать «приложениями, которые устанавливаются и на Android, и на iOS», а практически остаётся большим вопросом, насколько оправдано их использование вместо обычных приложений — но вероятно, что в будущем их поддержка продолжит улучшаться.

Что в итоге? Тем, кому хочется «уволить половину мобильных разработчиков», 2019-й не поможет: ни один из трёх описанных подходов не позволяет просто взять и реализовать всё универсально. Но вот тем, кому интересен любой возможный прирост эффективности (пусть и далеко не в два раза), стоит обратить внимание на все три.

Когда вариантов расплодилось так много, какую технологию выбрать для вашего нового приложения? Ответ скучный, но от того не менее истинный: у каждой свои преимущества и свои риски, и лучше, чтобы в команде был человек, способный принять взвешенное решение. Сможем ли мы реализовать всё, что нам нужно, в PWA? Будет ли скорость работы нашей команды максимальной с React Native? Возникнут ли проблемы с нативными фичами во Flutter? Есть ли у нас вообще люди со знаниями Kotlin/Swift? Ответы на все эти вопросы важны.

Если «лучшего» кроссплатформенного подхода не существует, то какой хотя бы станет самым популярным? Пока что невозможно сказать и это — но похоливарить в комментариях всё равно может быть весело.

А если вместо холиваров вы хотите закопаться в тему глубже — мы проводим конференцию Mobius, там в декабре было по докладу про Flutter и мультиплатформенный Kotlin, и из них можно узнать больше технических подробностей:

А на следующем Mobius, который состоится в Петербурге в мае, будет ещё один доклад о мультиплатформенном Kotlin — в этот раз с акцентом на то, что изменилось в версии Kotlin 1.3.

4040
39 комментариев

Спасибо, статья хорошая, добавил в закладки.

В отличие от Google и Facebook, которые зарабатывают на рекламе и хотят увидеть себя на как можно большем числе устройств, Apple не заинтересован в кросс-платформенной разработке (в Apple «кросс-платформенный» означает iOS + macOS + watchOS + tvOS).

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

А игнорировать iOS не получится — пользователей iOS меньше, но денег они приносят больше. Избавиться от нативной разработки не удастся, пока жив Apple.

15

Если не ошибаюсь, то приложения на ведре уже больше денег приносят или сопоставимо. Ну если не считать конечно количество прибыли на пользователя. По поводу "эксклюзивный функционал для своих пользователей, который затратно повторить на других платформах" можно хоть один пример того, что трудно повторить на андроиде и эпл специально какие-то палки в колеса вставляет? Насколько я знаю им пох, лицензия разработчика стоит $100 в год, неважно на чем ты писать будешь на реакте или нативе. Собрать ты все это сможешь все равно только на маке, если без боли в заднем проходе, и только если заплатил соточку

1

// Подождите, мы оказывались недовольны, если из двух кодовых баз получалось три, а нам предлагают сразу же именно так и сделать. В чём тогда смысл вообще?

Идея-то была в том, что из двух кодовых баз предполагается выделить общую абстрактную часть, не зависящую от конкретной платформы. Если действительно следовать принципам "чистой архитектуры" от дядюшки Боба (Роберта Мартина, не путать с Джорджем), то у нас получается, что у нас на каждую платформу есть две кодовых базы - с привязкой к фреймворку и полностью абстрактная логика. И переход на 3 базы означает экономию на одной абстрактной базе, которую все сейчас пишут заново.

Но есть две проблемы:
1. Практическое отсутствие действительно чистой архитектуры. Я работал в командах, которые декларировали чистую архитектуру под Андроид, но на деле это была просто удобная распилка на небольшие классы - но в каждом слое была привязка к конкретному фреймворку (Android). В то время, как "фреймворк - это деталь реализации" (с) Роберт Мартин в книге "Чистая архитектура". Следовательно, нет чистой абстрактной кодовой базы, которую можно было бы сделать общей, вообще нет привычки писать полностью оторвавшись от Андроида - отсылки к контексту и конкретным либам можно встретить на любом этапе логики.

2. в Андроид и iOS исторически сложился разный конкретный принцип "пиления" на отдельные классы - то, что называют "чистой архитектурой" из п.1 (которая, как я пояснил, часто не является чистой, так как в абстрактном слое нужна полная отвязка от платформы, от конкретных либ, даже от Rx, как бы это ни было тяжело). К примеру, в нашей команде iOS упарывался в хорошем смысле по VIPER, а Андроидеры фигачили разновидности MVC-MVVM.


Поэтому, когда Андроид-девелопере садились пилить на Xamarin, они писали общую часть по своим принципа, а iOS-отдел - хотел писать по своему. Это и создает дополнительные проблемы в кроссплатформе - столкновение "архитектурных привычек"

Универсальный-то выход по Роберту Мартину, который выстрадал свою точку зрения за десятки лет программирования (он кодил еще в 60х) - в таком пилении на классы, в такой архитектуре, в которой есть чистая логика, не привязанная к платформе, с объявленными интерфейсами, и блок реализации на конкретном фреймворке, платформе, устройстве. Тогда нам будет без разницы, какая ось победила в этом десятилетии и куда еще клиент хочет портировать свою программу - нам надо будет взять только часть кода, привязанную к конкретной реализации, и сделать ее для новой платформы.

6

"он кодил еще в 60х"
Сергей, ну Вы сравнили, мамонта из 60-х и современные практики разработки :) Это как авто на паровом двигателе сравнивать с Теслой.
Сейчас разработка ПО ускоряется, никому эти вот архитектуры не всрались:
"в таком пилении на классы, в такой архитектуре, в которой есть чистая логика, не привязанная к платформе, с объявленными интерфейсами, и блок реализации на конкретном фреймворке, платформе, устройстве"
Пока Вы будете писать свою идеальную архитектуру, конкуренты уже запустят продукт и словят хайп и бенефиты. А под конец разработки Вашей идеальной архитектуры придет Product Owner и своими бизнес-требованиями разнесет эту архитектуру в неудачную поделку. Или при тестировании выяснится, что надо все переделывать из проблем с производительностью или совместимостью.

Касательно iOS/Android, если приложение позволяет использовать Cordova или React Native - тут можно сэкономить на кодовой базе, если нет - то лучше и не пытаться.

4

Всё уже давно придумали, сделали, причём и код и UI, поддерживают не только Android и iOS, но так же весь десктоп и встраиваемые системы.
Технология проверенная десятилетиями.
Другое дело, что построена не на ванильных котлино-свифтовых-дарто-жс-жабах, а на языке, который, как известно, за 21 день не изучить - C++

Называется фреймворк Qt.
Code less, create more, deploy everywhere!

2

А сколько мегабайтов рантайма у qt под Андроид и как дела с нативно выглядящим UI?