что такое кроссплатформенная разработка
Кроссплатформенная разработка мобильных приложений – плюсы и минусы
Что такое кроссплатформенность?
Несколько команд разработчиков (по одной на каждую платформу) пишут приложения, используя нативные инструменты, они постоянно устраивают встречи, чтобы удостовериться, что приложения на разных платформах идентичны по функциональности и дизайну, что пользователь, перешедший с одной платформы на другую, сможет продолжить пользоваться приложением не испытывая никаких сложностей.
В итоге получается интересный результат: несколько приложений, которые реализованы на разных технологиях и языках программирования, но при этом выглядят одинаково и несут в себе одинаковый функционал. Именно в этот момент стоит вернуться к изначальному вопросу о том, что такое кроссплатформенность. Кроссплатформенный подход, в отличие от классического нативного, позволяет использовать одну кодовую базу для разных платформ, что избавляет от поддержки разных версий одного приложения. Разные фреймворки для кроссплатформенной разработки по-разному подходят к решению данной проблемы: одни компилируют код в нативный для определённой платформы, другие используют прослойки между платформой и кроссплатформенным кодом, но принцип все равно один: достаточно написать код один раз, который можно будет запускать сразу на нескольких платформах.
В этой статье я хочу сфокусироваться на мобильной разработке, рассмотреть преимущества и недостатки кроссплатформенного подхода и ответить на вопрос: «Стоит ли отказываться от классического подхода в сторону кроссплатформенности?».
Плюсы и минусы нативной разработки
Как уже упоминалось в введении, глобально мобильные приложения можно разделить на две категории: классические (далее будем называть их нативными) и кроссплатформенными, и я считаю, что перед погружением в мир кроссплатформенной разработки мобильных приложений необходимо подробней поговорить о нативных приложениях.
В мире мобильных устройств доминируют две платформы: iOS и Android. Для разработки приложений для этих систем компании Apple и Google выпустили соответствующие SDK. Приложения под Android разрабатываются с помощью Java или Kotlin в Android Studio, под iOS с помощью Swift в Xcode.
С первого взгляда не знакомому с темой человеку может показаться странным выбирать нативный подход, когда существует кроссплатформа. Зачем писать два приложения, когда можно написать одно? И действительно зачем, ведь можно так сильно облегчить себе жизнь, написав всего лишь одно приложение? Но как всегда в реальности все намного сложнее. Нативная разработка имеет ряд неоспоримых преимуществ, о которых я и предлагаю поговорить далее.
В первую очередь это актуальность. Именно нативные разработчики в первую очередь получают в свои руки все возможности новых версий операционных систем, будь то небольшое изменение иконок или новые полноценные API для улучшения и развития своего приложения. Кроссплатформенные разработчики в свою очередь вынуждены ждать, пока эти возможности добавят в используемый ими фреймворк, или пока кто-нибудь из сообщества не выпустит библиотеку, зачастую основанную на нативном коде.
Из-за особенностей внутренней работы кроссплатформенных фреймворков они так или иначе замедляют приложения, позволяя нативным приложениям вырвать победу в скорости работы приложений. Также фреймворки для кроссплатформенной разработки мобильных приложений, в отличие от нативной, не имеют полного доступа к API системы, заставляя разработчиков либо писать нативный код, либо искать библиотеку для решения их проблемы.
Подробнее о кроссплатформенных приложениях: особенности, преимущества, недостатки
Пришло время поговорить о кроссплатформенных приложениях. Из-за огромного разнообразия доступных фреймворков сложно выделить какие либо общие особенности, помимо, собственно, кроссплатформенного подхода, но все они имеют схожие плюсы и недостатки.
Главным плюсом кроссплатформенного подхода к разработке является решение главного недостатка нативной разработки, а именно необходимости иметь две команды разработчиков и поддерживать две кодовые базы. В этом и состоит вся суть подобных фреймворков и подхода в целом — удешевить и ускорить разработку. При выборе такого подхода понадобится лишь одна команда разработчиков, у вас будет одна кодовая база, все новые фичи будут выходить одновременно на всех платформах.
Но решение этого недостатка вызывает сразу несколько других. Скорость работы кроссплатформенных приложений в общем ниже, чем у нативных, например, это будет заметно в приложениях с тяжелой анимацией. Как уже было упомянуто, у кроссплатформенных приложений ограниченный доступ к API операционной системы, что может привести к необходимости писать нативный код. Хотя стоит отметить, что нативный код достаточно просто встраивается в кроссплатформенный, но если часто прибегать к такому решению, подход лишится своего главного преимущества. Также решением этой проблемы могут быть библиотеки, написанные другими разработчиками, что позволит не дробить кодовую базу на кроссплатформенные и нативные составляющие, но он не сможет защитить вас от багов и недоработок самой библиотеки.
Но если ваше приложение не сильно использует возможности платформы, например, камеру смартфона, выбрав кроссплатформенную разработку вы сможете не только сильно сэкономить на стоимости разработки, но и в скорости, за счет удобных для разработчиков инструментов, о которых поговорим далее.
На чем разрабатывают кроссплатформенные приложения: инструменты и платформы
Существует огромное количество фреймворков для разработки кроссплатформенных мобильных приложений, но наиболее широкое продуктовое применение получили React Native и Flutter, на которых мы сфокусируемся.
Начать стоит с React Native, кроссплатформенного фреймворка от Facebook, построенного на основе сверхпопулярной JS библиотеки, React Native делает переход от web-разработки к мобильной максимально простым. Технология Fast Refresh позволяет практически мгновенно отображать изменения в коде на устройстве, тем самым сильно ускоряя разработку приложения. Так как фреймворк основан на React Js разработка на нем осуществляется с помощью JavaScript, позволяя front-end разработчикам быстро переключиться на разработку кроссплатформенных мобильных приложений.
И хотя у React Native есть определенные проблемы с производительностью, он все еще остается самым популярным кроссплатформенным фреймворком с огромным комьюнити, поддерживающим гигантское количество библиотек, что в свою очередь еще сильнее ускоряет разработку и облегчает поиск новых разработчиков. Но конкурент React Native от Google все ближе и ближе подбирается к его популярности.
Flutter — относительно молодой фреймворк, выпущенный в 2017 году, но, несмотря на небольшой возраст, он заработал большую популярность в сообществе разработчиков. Flutter постоянно развивается. Изначально представленный как фреймворк для кроссплатформенной мобильной разработки, он уже перерос это определение. Сейчас на основе набора средств Flutter можно разрабатывать мобильные, web и desktop приложения. Hot Reload по аналогии с Fast Refresh в React Native, позволяет мгновенно увидеть изменение на экране устройства, а большое количество библиотек практически полностью закрывает собой ограниченный доступ к API системы (хотя в выборе библиотек нужно быть осторожным, так как некоторые из них могут не поддерживать чать платформ) и дает возможность свести написание нативного кода к минимуму или отказаться от него совсем.
Разработка на Flutter происходит на языке Dart, который также разрабатывается Google, что в свою очередь позволяет добавлять в язык новые возможности специально для Flutter разработчиков. Так недавно из беты вышла функция null safety, которая при включении ее в проект обвязывает разработчиков специально помечать переменные, значение которых может быть null, и добавлять проверки на такие случаи, что в итоге приводит к более высокой стабильности приложения. Dart также прост для изучения для нативных разработчиков, что дает им возможность при желании быстро переключиться на кроссплатформенную разработку.
Кейс Doubletapp
Сотрудники компании могут всего в пару кликов запросить зарплату или аванс, просмотреть накопившиеся отпускные дни и запросить отпуск, использовать больничный в случае болезни, для похода к врачу или покупки лекарств, а также отправлять запрос на компенсацию дополнительных трат: на образование, конференции, покупку ПО или устройств, необходимых для работы.
Руководство компании в то же время может выплачивать сотрудником зарплату, одобрять их заявки на отпуск и дополнительные траты, легко добавлять и просматривать любые расходы и доходы, осуществлять переводы между счетами компании.
Flutter позволил нам небольшими усилиями и в кратчайшие сроки запустить приложение на всех актуальных платформах, тем самым давая возможность сотрудникам и руководству пользоваться системой на удобных для них платформах.
Наше приложение мало пользуется специфичными для определенных платформ возможностями, поэтому мы полностью избежали написания нативного кода для каждой из доступных операционных систем. Небольшие проблемы возникли лишь с доступом к камере мобильных устройств для чтения QR-кодов, с помощью них сотрудник может отметить, что он забрал устройство из офиса к себе домой, но мы быстро нашли библиотеку, которая решала нашу проблему, тем самым нам удалось сохранить единую кодовую базу для всех платформ.
Выводы
Так стоит ли отказываться от нативной разработки в пользу кроссплатформенной? Ответ на этот вопрос зависит полностью от вашего приложения, вашего бюджета и времени, которые вы готовы потратить на разработку.
Нативные приложения все еще сильно опережают кроссплатформенные по производительности и функционалу, но разработка таких приложений занимает много времени и средств, кроссплатформенная разработка в то же время, хоть и не лишена недостатков, позволяет за короткий промежуток времени создать приложение сразу для нескольких платформ.
В итоге, если ваше приложение не полагается на особенности конкретных платформ или бюджет на разработку ограничен, стоит рассмотреть кроссплатформенное решение, в обратном же случае, хоть с помощью библиотек можно попытаться решить проблему недостаточного доступа к API системы, стоит обратить внимание на наивную разработку.
Кроссплатформенная мобильная разработка: история вопроса
Когда речь заходит о разработке «сразу для Android и iOS», начинаются холивары и гадания на кофейной гуще. Что перспективнее, Flutter или Kotlin Multiplatform Mobile? За этими технологиями будущее, или завтра их обе забудут?
Уверенно делать прогнозы по принципу «я так вижу» — занятие весёлое, но бессмысленное. Как подойти конструктивнее? Как известно, «кто забывает об истории, обречён на её повторение». Поэтому я решил вспомнить, какими были решения «Android+iOS» до Flutter/KMM, и посмотреть, что с ними стало. Тогда вместо голых спекуляций будут суровые факты. И эти факты из прошлого полезны для понимания будущего: они показывают, где разложены грабли.
Большинство старых технологий я не использовал лично, но благодаря общению со спикерами нашей конференции Mobius узнал многое об их опыте с этими решениями. Если вы тоже работали с чем-то из перечисленного, смело дополняйте в комментариях, будет интересно и полезно.
Оглавление
Web / PWA
В 2007-м, представляя разработчикам первый iPhone, Стив Джобс объяснял, что нативные приложения не нужны: «В iPhone есть полный движок Safari. Так что можете писать потрясающие Web 2.0 и Ajax-приложения, которые выглядят и действуют на iPhone именно как приложения».
Android на тот момент ещё даже не был анонсирован. Но получается, что исторически первым единым решением для iOS и Android стал веб.
Вот только разработчики не разделили энтузиазм Джобса (неудивительно, учитывая тогдашнее состояние мобильного интернета). И годом позже всё-таки появился App Store для нативных приложений. А его комиссия в 30% стала новым денежным потоком для Apple. В итоге позиция компании сменилась на противоположную: теперь она считает, что правильный подход — это натив (и предпочитает не вспоминать, что там её лидер говорил в 2007-м, Океания всегда воевала с Остазией).
Однако идея веб-приложений не исчезла, а продолжила развиваться. И в 2015-м новое поколение таких приложений назвали «Progressive Web Apps». Они могут хранить данные локально, работать в офлайне, а ещё их можно установить на домашний экран смартфона. Чем это тогда не «настоящие» мобильные приложения? Что ещё для счастья надо?
Ну, например, для счастья нужны push-уведомления. По состоянию на 2021-й iOS не поддерживает их у PWA, и это мощнейший стопор для распространения подхода. Получается, компания, которая первой хвалила веб-приложения, позже сама поставила главное препятствие на их пути. На change.org есть даже петиция, обращённая к Apple: «мы всё понимаем, вы дорожите своими 30%, но эта ситуация должна измениться».
Что в итоге: подход жив, но не стал общепринятым — во многом из-за ограничений Apple. В будущем что-то может измениться, стоит следить.
PhoneGap/Apache Cordova
Это решение тоже связано с вебом, но подход другой — так называемый «гибридный». Тут предложили использовать знакомую троицу HTML/CSS/JS, но результат не публиковать в виде сайта, а упаковать в «контейнер» нативного приложения. В таком случае не сталкиваешься с ограничениями веба и можешь реализовать те же push-уведомления.
PhoneGap появился в 2009-м благодаря компании Nitobi, а в 2011-м Adobe купила её и выделила основу в опенсорсный проект Apache Cordova. У него модульная архитектура, позволяющая подключать плагины. И в сочетании с опенсорсностью это означает, что если Cordova не умеет чего-то нужного (например, взаимодействовать с акселерометром смартфона), сообщество может «научить». Вроде как прекрасно, да?
На практике что-то не очень. В своё время некоторая популярность у проекта была, те же плагины появлялись, но масштабного «захвата рынка» не произошло. А затем всё и вовсе пошло на спад.
Почему так? Среди главных причин называют UX, уступающий нативным приложениям. Всё хуже и с производительностью, и с плавностью. Но основное отличие даже не измерить числами: пользователю попросту заметна разница между гибридным приложением и нативным, они производят разное впечатление. Для людей «через WebView ощущения не те».
А с годами сказалось ещё и развитие веба. Чем лучше становились веб-приложения и чем быстрее становился мобильный интернет, тем меньше преимуществ можно было получить от гибридного подхода.
Интересно, что авторы проекта сами предвидели такое развитие событий и ещё в 2012-м написали, что «итоговая цель PhoneGap — прекратить своё существование». И недавно эта цель была достигнута: в 2020-м Adobe заявили о прекращении разработки PhoneGap, ссылаясь на то, что нишу закрыли PWA. Cordova как опенсорсный проект формально жив, но без участия Adobe вряд ли стоит ожидать в нём большой активности.
Что в итоге: по сути, проекта больше нет.
Проект Qt помогал людям заниматься кроссплатформенной разработкой ещё с 90-х, когда ни о каких айфонах слыхом не слыхивали, и речь шла о десктопных ОС. При этом он завязан на C++, который для Android и iOS не совсем чужой: даже нативные разработчики на этих платформах могут обращаться к «плюсам». Так что, казалось бы, поддержка iOS/Android со стороны Qt просто напрашивалась.
Но поначалу дело осложнялось тем, что в 2008-м проект купила Nokia. Компания тогда делала ставку на Symbian и не горела желанием помогать конкурентам. В 2010-м возможностью запускать Qt-приложения на Android занимались энтузиасты, и на Хабре об этом писали:
В 2011-м Nokia отказалась от Symbian в пользу Windows Phone, а часть проекта Qt продала компании Digia. И тогда началась работа над поддержкой одновременно Windows 8, Android и iOS. Ну вот теперь-то счастье? Спустя 10 лет ясно, что тоже нет.
Вакансии по мобильной разработке на Qt сейчас единичные. Хабрапосты о ней появляются очень редко и не свидетельствуют об успехе: в одном причиной использования Qt стала ОС «Аврора» (экс-Sailfish), в другом попросту «у меня уже был большой опыт с ним».
Что помешало? Я встречал жалобы на то, что недостаточно было использовать сам Qt и писать на С++/QML. Потому что средствами Qt многое было не реализовать, и приходилось-таки иметь дело с конкретной платформой (например, на Android работать с Java, увязывая это с «плюсовой» частью через JNI). Всё это очень неудобно и подрывает исходную идею «бодренько запилим два приложения по цене одного».
При этом здесь пользователь тоже ощущает «не-нативность». А к IDE Qt Creator есть нарекания, рантайм Qt увеличивает размер приложения, бесплатный вариант Qt подходит не всегда и может понадобиться недешёвый коммерческий. Кроме того, мне лично кажется, что ещё сказался язык. Кроссплатформенной разработке желательно быть такой, чтобы нативным разработчикам было попроще перекатиться туда, а с языком C++ слово «попроще» не ассоциируется.
И хотя случаи использования Qt встречаются до сих пор, это скорее исключения из правил, у которых могут быть какие-то особые исходные условия: например, «хотим перетащить на телефоны с десктопа уже имеющуюся кодовую базу на C++».
Что в итоге: крайне нишевое решение, которое не умерло, но используется очень узкой прослойкой.
Xamarin
Надо понимать контекст того времени. Годом ранее компания Microsoft выпустила Windows Phone и стремилась стать третьим большим игроком на мобильном рынке. И даже «большая» Windows лезла на мобильный рынок: готовилась к выходу Windows 8, оптимизированная для планшетов.
В таком контексте идея «писать под все смартфоны на языке от Microsoft» выглядит логично. Ведь если для кроссплатформы применяется «родной» язык одной из главных платформ, то он уже знаком части мобильных разработчиков, и они могут переиспользовать что-то из существующих кодовых баз. В общем, будет проще «наводить мосты».
Но теперь задним числом мы знаем, что мобильные амбиции Microsoft заглохли. И это оставило Xamarin в странном положении: на рынке две живых платформы, а тут предлагают писать для обеих на языке умершей третьей. Ни айосеров, ни андроидоводов такое сильно не привлекает.
Ещё порой вызывали недовольство и то, что после появления новых фич в Android/iOS приходилось ждать их поддержки в Xamarin, и стоимость лицензии, и общее состояние экосистемы (документация, поддержка, библиотеки).
Что в итоге: пока всё остаётся в странноватом статусе, когда и масштабного взлёта не получилось, и полностью не прекращено.
React Native
В 2013-м в Facebook выпустил React, ставший очень успешным во фронтенде, а в 2015-м за ним последовал React Native, приносящий подход в мобильную разработку.
Писать предлагается на JavaScript, поэтому кому-то может показаться, что это реинкарнация PhoneGap и его HTML-подхода, но нет. Когда-то Facebook действительно полагался для мобильных устройств на HTML, но ещё в 2012-м Цукерберг назвал это ошибкой. И у React Native идея не в том, чтобы с помощью HTML/CSS городить что хочешь, а в том, чтобы с помощью JSX использовать нативные элементы UI — так что пользователь ощущал себя «прямо как с нативным приложением».
Насколько это получилось? Шероховатости и «срезанные углы» существуют — с ними сталкиваются и разработчики, и пользователи. Для кого-то они оказываются критичными: особенно нашумел пост Airbnb, где после React Native решили вернуться к нативной разработке. Но какие-то другие компании (вроде самой Facebook) эти ограничения не остановили, использование в индустрии есть.
Поскольку нативной «отполированности» не достичь, это решение часто рекомендуют для случаев, где она и не требуется. Если пользователь залипает в приложении часами (как в соцсетях), то любая неаккуратная мелочь будет бросаться ему в глаза — но вот если юзкейс приложения такой, что его включают на минуту в неделю, то эти мелочи просто никто не заметит.
Если зайти на HeadHunter и сравнить число вакансий по React Native с нативной разработкой, то их немного. Но вот если сравнивать с Qt/Xamarin/PhoneGap — то вакансий окажется больше, чем у них всех, вместе взятых, это наиболее успешный вариант.
Что в итоге: React Native не стал так успешен, как его фронтендовый «старший брат», но определённую нишу занял.
Flutter, KMM и выводы
А теперь, после всего перечисленного, у нас появились новые решения: Flutter и Kotlin Multiplatform Mobile.
Первое от Google, сначала появилось как решение для Android и iOS, а позже заявили также о поддержке десктопа и веба. Flutter предлагает писать на языке Dart и считает весь экран своим холстом: не обращается к нативному UI, как React Native, а рисует что хочет, так что можно делать смелые необычные интерфейсы. Но если хочется не смелости, а чтобы пользователю было привычно, в комплект входит имитация стандартных UI-элементов из Android и iOS.
Второе решение — от JetBrains, и оно совершенно не считает весь экран своим холстом. Оно вообще не про общий UI, а только про общую бизнес-логику — остальные вещи предлагается на каждой платформе делать раздельно. KMM — лишь часть большой инициативы «мультиплатформенного Kotlin»: компания хочет, чтобы люди писали на Kotlin почти всё (и бэкенд, и фронтенд, и мобильные приложения, и не только), переиспользуя часть кода между этим всем.
Пока прошло недостаточно времени, чтобы точно понять, насколько эти два решения окажутся успешны. Но можно ли из опыта предшественников извлечь какие-то выводы, помогающие сделать прогноз?
Обычно в холиварах занимают крайние позиции: «эта крутая штука всех победит» или «все эти глупости скоро отомрут». А у меня после изучения прошлого опыта позиция получилась сдержанной:
«Победит» и «умрёт» — не единственные варианты. Зачастую технология занимает небольшой сегмент рынка и не претендует на мировое господство, но приносит кому-то пользу.
Кроссплатформа — это всегда компромисс. Выдержать планку качества, заданную нативом, не получалось нигде. Везде что-то «вытарчивает» — и пользователи могут заметить разницу, и разработчикам приходится возиться со сложностями. И далеко не для всего кроссплатформа подходит одинаково: если бизнес-логика между платформами шарится хорошо, то с вещами вроде UI всё сложнее.
Но качество ниже нативного не означает, что кроссплатформа плоха и не нужна. Кому-то на этот компромисс вполне стоит идти (например, стартапу, где вся жизнь — один сплошной компромисс). В каждом проекте надо взвешивать свои «за» и «против», и результаты в разных случаях будут различаться.
И всё это приводит меня к такому выводу про Flutter: вместо обсуждений «выиграет он или проиграет» надо обсуждать «в каких конкретно юзкейсах он выигрывает». По-моему, он хорош для определённой ниши, поэтому вряд ли угрожает будущему нативной разработки (она никуда не денется), но закрепиться вполне может. Вопрос в том, каковы размеры этой ниши и попадает ли в неё ваш проект.
А вот про Kotlin Multiplatform Mobile сделать выводы по прошлому у меня не получилось, потому что у него нетипичная ситуация. Во-первых, идея «кроссплатформа годится не для всего» тут заложена прямо в фундамент: «а мы и не предлагаем объединять всё, реализуйте только общую бизнес-логику». Во-вторых, тут играет на руку «родной» для Android язык: он уже знаком половине мобильных разработчиков, и такого в кроссплатформе раньше не возникало. В-третьих, многое зависит от того, насколько Kotlin «взлетит» за пределами мобильной разработки. Так что опыт предыдущих технологий тут непоказателен — остаётся смотреть, что покажет время.
На последнем Mobius было сразу несколько кроссплатформенных докладов (три про Flutter, один про Kotlin Multiplatform) — мы уже выложили все видеозаписи конференции на YouTube, так что можете сами их посмотреть. А мы тем временем вовсю работаем над следующим Mobius: он пройдёт 13-16 апреля в онлайне, и там без освещения кроссплатформы тоже не обойдётся. Так что, если вас заинтересовал этот пост, то вам будет интересно и там.