Дорогой друг, если ты готов узнать больше про архитектуры популярных кроссплатформенных мобильных фреймворков, именно в этой статье мы проведем их сравнение и определим, для какого класса задач или команд подходит тот или иной инструмент. В первой части рассмотрим общие архитектурные паттерны кроссплатформенных фреймворков, а также архитектуры PhoneGap и ReactNative. Во второй части — фреймворки Xamarin и Qt.



Данная статья является сокращенной версией руководства, доступного по ссылке в конце.

Передаю слово Вячеславу Черникову.

Введение


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


В качестве целевых платформ мы остановимся на iOS, Android и Windows UWP.


Нативные и кроссплатформенные инструменты разработки


Исторически на рынке компьютеров всегда была конкуренция и каждый производитель предоставлял оптимальный набор так называемых «нативных» (родных) инструментов для разработки приложений под свои операционные системы и устройства. “Нативные” средства разработки обеспечивают оптимальную производительность и доступ к возможностям операционной системы.


Однако часто оказывалось, что эти инструменты были несовместимы друг с другом не только на уровне языка разработки, принятых соглашений и архитектур, но и на уровне механизмов работы с операционной системой и библиотеками. В результате для реализации одних и тех же алгоритмов, пользовательских или бизнес-сценариев требовалось написать приложение для нескольких сред на разных языках программирования. Например, если надо поддерживать 2 платформы, то требуется увеличение трудозатрат и команды в 2 раза. Плюс в 2 раза больше бюджетов на поддержку и развитие. Можно добавить, что во многих компаниях уже скопилась большая база кода, который также хотелось бы унаследовать в новых решениях.


Вторым важным моментом является наличие необходимых компетенций (знаний и опыта) внутри команды – если их нет, то потребуется время на обучение.


Для того, чтобы решить обе этих проблемы, на рынке появились инструменты кроссплатформенной разработки, предлагающие:


— максимизировать общую базу кода на едином языке программирования, чтобы продукт было проще разрабатывать и поддерживать;


— использовать существующие компетенции и специалистов для реализации приложений на новых платформах.


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


Общая база кода. В зависимости от выбранного инструмента разработчик сможет шарить между платформами: ресурсы приложения (картинки, шрифты и прочие файлы), логику работы с данными, бизнес-логику и описание интерфейса. И если с ресурсами и логикой (обработки данных и бизнес-) все довольно просто, то вот с интерфейсом следует быть осторожнее, так как для каждой из платформ есть свои рекомендации и требования.



Использование существующих компетенций и команды. Здесь стоит учитывать не только язык программирования, но и понимание механизмов работы операционных систем iOS/Android/Windows, а также набор дополнительных библиотек и инструментов разработки.



Итак, «нативные» инструменты предоставляются самими владельцами экосистем и позволяют получить максимум из возможностей целевой операционной системы, имеют полный доступ к родным API, оптимальную производительность и требуют отдельной команды разработки под каждую платформу.


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


Архитектура iOS/Android и нативные API


Главный принцип, лежащий в основе кроссплатформенных решений — разделение кода на 2 части:


  • кроссплатформенную, живущую в виртуальном окружении и имеющую ограниченный доступ к возможностям целевой платформы через специальный мост;
  • нативную, которая обеспечивает инициализацию приложения, управление жизненным циклом ключевых объектов и имеющую полный доступ к системным API.


Для того, чтобы связывать между собой мир “нативный” и мир “кроссплатформенный”, необходимо использовать специальный мост (bridge). И как мы увидим в главе 3, именно bridge и определяет возможности и ограничения кроссплатформенных фреймворков.


Использование bridge всегда негативно сказывается на производительности за счет преобразования данных между “мирами”, а также конвертации вызовов API и библиотек. Сам по себе “кроссплатформенный” мир имеет сопоставимую с “нативным” производительность.

Итак, все кроссплатформенные приложения обязаны иметь нативную часть, иначе операционная система просто не сможет их запустить. А сами iOS, Android и Windows UWP предоставляют необходимые API для работы кроссплатформенных фреймворков:


  • WebView используется в гибридных приложениях на базе PhoneGap или аналогов для запуска приложений и фактически выступает средой выполнения веб-приложений;
  • JavaScript-движки используются в ReactNative и аналогах для быстрого выполнения JS-кода и обмена данными между Native и JS;
  • OpenGL ES (или DirectX) используется в играх и приложениях на Qt/QML или аналогах для отрисовки интерфейса;
  • UI-подсистема отвечает за нативный пользовательский интерфейс приложения, что актуально для ReactNative и Xamarin.

Более подробное описание данных подсистем в различных операционных системах вы можете найти в полной версии руководства по ссылке в конце статьи.


Архитектуры кроссплатформенных фреймворков


Все операционные системы имеют те или иные технические возможности по запуску кроссплатформенных приложений. Самое простое с технической точки зрения — использование WebView, которое есть у всех ОС (актуально для PhoneGap). Вторым вариантом является использование механизмов низкого уровня вроде OpenGL ES и языка C/C++ — это позволит разделять между проектами большинство логики (в играх или Qt), но будет ограниченно работать (или не работать) на Windows UWP. Если же вам будет нужен полностью нативный пользовательский интерфейс и нативная производительность с минимальными накладными расходами, то здесь начинают задействоваться системные API верхнего уровня — такой подход реализуется в Xamarin и ReactNative.


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



PhoneGap


Решения на базе PhoneGap используют WebView и являются достаточно простыми с точки зрения реализации — создается небольшое нативное приложение, которое фактически просто отображает встроенный веб-браузер и single-page HTML. Нет никаких нативных контролов и прямого доступа к API — все интерфейсные элементы внутри веб-страницы просто стилизуются под родные. Для доступа к системной функциональности подключаются специальные плагины, которые добавляют JS-методы внутрь веб-браузера и связывают их с нативной реализацией на каждой платформе.



Как видим, PhoneGap позволяет разделять практически весь код между платформами, однако все еще требуется реализация нативной части на Objective C и Java (и C# для Windows). Вся жизнь приложения проходит внутри WebView, поэтому веб-разработчики почувствуют себя как рыба в воде. До тех пор, пока не возникнет потребность в платформенной функциональности — здесь уже будет необходимо хорошее понимание iOS и Android.


Также PhoneGap (он же Apache Cordova) используется в популярном фреймворке Ionic, который предоставляет большое количество готовых плагинов для системной функциональности.


Интерфейс приложений на основе WebView не является нативным, а только делается похожим на него с помощью HTML/CSS-стилей.

При разработке приложений на PhoneGap требуется опыт HTML, JavaScript, CSS, а также Objective C, Java и хорошие инженерные знания для интеграции нативной и кроссплатформенной частей. Пользовательский интерфейс организован по принципу одностраничного HTML — в реальных приложениях со сложным интерфейсом будут подергивания и подтормаживания (особенности мобильных WebView, которые еще и могут отличаться у разных производителей). Для передачи данных через мост их необходимо сериализовать/десериализовать в Json. В целом, мост используется редко, так как вся жизнь приложения проходит внутри WebView.


Для передачи сложных структур данных и классов между нативной частью и WebView их необходимо сериализовать/десериализовать в формате JSON.

Напоследок отметим, что PhoneGap уже достаточно зрелое решение с большим количеством готовых плагинов.


Итак, PhoneGap можно рекомендовать для быстрой разработки простых приложений (до 15 экранов) с небольшой пользовательской аудиторией (например, решение внутри компании) или прототипов.

ReactNative


Одним из интересных решений в области кроссплатформенной разработки мобильных приложений является ReactNative, созданный в Facebook. Этот фреймворк дает возможность использовать JavaScript для описания нативного интерфейса и логики работы приложений. Сам по себе JS-движок обеспечивает производительность, сопоставимую с нативной. Однако не стоит забывать, что и в архитектуре ReactNative присутствует мост, снижающий скорость работы с платформенной функциональностью и UI.



При создании приложений на ReactNative разработчику будет необходимо также реализовывать нативную часть на Objective C, Java или C#, которая инициализирует JS-движок и свой JS-код. Далее JS-приложение берет управление в свои руки и при помощи ReactNative начинает создавать нативные объекты и управлять ими из JavaScript. Стоит добавить, что архитектура ReactNative позволяет осуществлять обновление JS-кода без перезапуска приложения (hot reloading). Это допускает обновление кроссплатформенной части без необходимости перепубликации приложений в AppStore и Google Play. Также можно использовать библиотеки из Npm и большое количество сторонних плагинов.


Необходимо учитывать, что из-за ограничений iOS (нет возможности реализовать JIT) код JavaScript на лету интерпретируется, а не компилируется. В целом это не сильно сказывается на производительности в реальных приложениях, но помнить об этом стоит.


Для передачи сложных структур данных и классов между нативной частью и JS-движком их необходимо сериализовать/десериализовать в формате JSON.

При создании приложений на ReactNative требуется опыт JavaScript, а также хорошие знание iOS и Android. Интеграцию нативной и кроссплатформенной частей легко сделать по официальной документации. Пользовательский интерфейс является полностью нативным, но имеет ограничения и особенности при стилизации из JS-кода, к которым придется привыкнуть. Для передачи данных через мост их необходимо сериализовать/десериализовать в Json. Плюс мост используется для управления нативными объектами, что также может вести к падению производительности при неэффективном использовании (например, часто менять свойства нативных UI-объектов из JS-кода при анимациях в ручном режиме).


Также следует учитывать юность фреймворка — имеются узкие места или ошибки, о которых узнаешь только во время разработки. И практически всегда требуется реализация нативной части на Objective C и Java.


Итак, ReactNative можно рекомендовать для быстрой разработки приложений средней сложности (до 40 экранов), в команде должны быть не только опытные JS-разработчики, но и хорошие специалисты по iOS (ObjC/Swift) и Android (Java/Kotlin).




Полную версию руководства вы можете найти на GitBook.

31 октября Вячеслав также будет выступать на нашем вебинаре Mobile DevOps для Xamarin-разработчиков, ускоряем тестирование и поставку. Участие как всегда бесплатное.

Напоминаем, что во второй части обзора мы подробнее остановимся на Xamarin и Qt, а также общих рекомендациях в выборе фреймворка. Оставайтесь на связи и задавайте свои вопросы в комментариях!

Об авторе


Вячеслав Черников — руководитель отдела разработки компании Binwell, Microsoft MVP и Xamarin Certified Developer. В прошлом — один из Nokia Champion и Qt Certified Specialist, в настоящее время — специалист по платформам Xamarin и Azure. В сферу mobile пришел в 2005 году, с 2008 года занимается разработкой мобильных приложений: начинал с Symbian, Maemo, Meego, Windows Mobile, потом перешел на iOS, Android и Windows Phone. Статьи Вячеслава вы также можете прочитать в блоге на Medium.

Другие статьи автора вы можете найти в нашей колонке #xamarincolumn.

UPD: Вторая часть здесь.

Комментарии (13)


  1. Virviil
    16.10.2017 15:46

    Я, как настоящий хипстер, хочу писать Xamarin.Forms на F# в VSCode на своём Arch linux.
    Скажите пожалуйста, это когда-нибудь будет возможно?


    1. znsoft
      16.10.2017 17:25

      разрабы xamarin говорят что не планируют этого forums.xamarin.com/discussion/1599/xamarin-studio-in-linux,
      хотя юнити тоже когда-то так утверждали, но таки запилили ее под линуксы, правда на слабых видеокартах запустить нормально все-равно не получается (


      1. Virviil
        16.10.2017 17:48

        Ну Unity подразумевает что я делаю графиконагруженные игрухи. А тут — как бы ничего не подразумевается.
        А на счёт F# что?


        1. znsoft
          17.10.2017 07:19

          насчет F# и VSCode не знаю т.к не использую. Юнити я привел в пример того, что он построен на той же технологии что и xamarin — (пока еще) mono.


  1. vitanje
    16.10.2017 16:20

    Отлично! Ждем вторую часть. Интересует в частности разработка на Qt


  1. yabivipil
    17.10.2017 11:53
    +1

    При создании приложений на ReactNative разработчику будет необходимо также реализовывать нативную часть на Objective C, Java или C#, которая инициализирует JS-движок и свой JS-код.

    Неакутально вроде уже. Там теперь все через expo делается. линк


    1. Vadem
      17.10.2017 18:34

      К сожалению, инфа по ReactNative устаревает достаточно быстро.
      Хотя Expo, вроде как, больше года назад появилось.


    1. devious
      17.10.2017 23:02

      Ну здесь все просто :) В реальных проектах практически всегда требуется доработка UI-контролов и часто нужен доступ к какой-нибудь специфической нативной функциональности (вроде фоновой синхронизации), которую хочешь или не хочешь, но надо делать на Objective C и Java.

      Про Expo полезное дополнение, спасибо!


  1. R2D2_RnD
    17.10.2017 11:53

    Оценка экономии трудозатрат в количестве строк shared-кода это несколько лукаво.
    Лукаво прежде всего потому что (как минимум в случае Xamarin) нет линейной зависимости между человеко-часами и итоговым количеством строк кода — и IDE играет в этой зависимости далеко не последнюю роль.
    Из особенностей Xamarin, которые солидно увеличивают количество человеко-часов можно отметить:
    — иногда бесконечное время сборки проекта (как правило это лечится удалением папок bin / obj)
    — периодическими отваливаниями отладчика после обновлений Xamarin


  1. MOHUS
    17.10.2017 18:42

    Хочу предложить другое деление по типам архитектуры.
    image


    Среди кросс-платформенных принципиальное деление на "нативные" и "гибридные".
    Нативные это те где вам просто предлагается программировать на одном языке под все платформы, но обычно вам надо осваивать на каждой платформе API этой платформы.
    Гибридные это те где весь код, а это HTML/CCS/JS запускается в WebView в котором у вас есть доступ не только к обычному набору API браузера но и к различным дополнительным API для доступа к различному функционалу недоступному из браузера.
    Особый тип — смешано гибридные, это когда у вас UI реализован в WebView, а логика/работа с данными реализована на каком то языке в полностью переносимой среде.
    На представленной схеме полностью переносимый код выделен зеленым.
    Мы в компании Tau Technologies занимаемся разработкой решения, Rhomobile, как раз смешанно-гибридного типа и считаем такую архитектуру наиболее перспективной для применения в корпоративной сфере.
    Собственно за что справедливо ругают такое самое распространенное решение как Cordova/PhoneGap? За то что у вас все висит в однопоточном WebView. Соответственно как только речь заходит о разработке больших приложений начинаются лаги, тормоза и т.п. Какое решение этой проблемы? Надо вынести код логики/работы с данными вовне WebView. Конечно этот код должен быть переносимым и т.п. Но как это сделать? Можно пойти путем нативных кросс-платформенных решений типа Xamarin, то есть заставить разработчиков учить новые для них API и т.п. Однако можно пойти другим путем — можно предоставить разработчикам какую-либо уже распространенную среду(есс-но и язык тоже). И тут явно напрашивается архитектура клиент-сервер веб приложения — ведь по сути у на сто же самое — WebView в которой клиент и UI и находящийся вовне сервер где код логики и работы с данными. И все что нам надо это перенести сервер прямо на мобильное устройство!
    В своем решении Rhomobile мы предлагаем две возможности для написания переносимого кросс-платформенного кода вне WebView (в которой реализуется легковесный UI) — это:


    • язык Ruby и среда Ruby on Rails
    • язык Javascript и среда Node.js
      Все это собирается в итоге в законченное платформенное приложение, причем все работает прямо на мобильном устройстве!
      Какие главные достоинства такого подхода:
    • переносимость кода. В корпоративном решении мобильное приложение это обычно всего лишь часть большой системы, которая обычно включает в себя и веб порталы и десктоп приложения и т.п. В случае применения смешанно-гибридного типа вы можете переносить код не только UI между веб порталом и приложением но и серверный код тоже! Более того код UI переносим не только между порталом и приложением но и между различными решениями гибридного типа!
    • эффективное использование разработчиков. Вам не надо набирать команду мобильных разработчиков и не надо обучать разработчиков новым API и т.п. Вы можете использовать своих разработчиков веб клиент-серверных решений и для разработки мобильных приложений без переучивания!


    1. MOHUS
      17.10.2017 19:01

      Эти вопросы я и мой коллега освещали в прошлом году в своем докладе на CEE SECR 2016:
      "Настоящее и будущее решений для разработки кросс-платформенных мобильных гибридных приложений в корпоративной сфере"
      http://files.tau-technologies.com/Events/2016_10_CEE_SECR/TAU_Technologies_CEE_SECR_2016_RUS.pdf
      В этом году у нас тоже будет (в эту субботу 21 октября 2017, в Санкт-петербурге) доклад на CEE SECR 2017 (пока не выложен, но будет выложен в день доклада):
      http://2017.secr.ru/program/submitted-presentations/improvement-of-hybrid-solutions-for-the-development-of-cross-platform-mobile-applications
      в этом году упор будет именно на смешанно-гибридную архитектуру и демонстрация как это выглядит вживую, когда Ruby on Rails или Node.js работают прямо на мобильном устройстве.


      Если кто интересуется как выглядит работа RoR или Node.js прямо на мобильном устройстве — вот пара наших докладов:
      "Rhomobile. Разработка кросс-платформенных мобильных гибридных приложений с использованием Ruby" (на RailsClub 2016)
      http://files.tau-technologies.com/Events/2016_10_RailsClub/Rhomobile_RailsClub_2016_full_RUS.pdf


      "Разработка кросс-платформенных мобильных гибридных приложений на базе Node.js с использованием Rhomobile" (на Node.js SPb Meetup 2017)
      http://files.tau-technologies.com/Events/2017_03_31_SPB_Nodejs_meetup/Rhomobile_SPB_Nodejs_meetup_2017_03_31_RUS.pdf


      1. devious
        17.10.2017 22:59

        Спасибо за полезные ссылки!


    1. vintage
      19.10.2017 21:23

      За то что у вас все висит в однопоточном WebView. Соответственно как только речь заходит о разработке больших приложений начинаются лаги, тормоза и т.п.

      На самом деле WebView не такой уж и однопоточный. Композиция и соответствующие анимации, не требующие перерисовки, происходят в отдельном потоке. Тормоза начинаются если анимации делаются на JS и если пытаться рендерить сразу все элементы, в то время как видимыми из них будут хорошо если 5%. Мы пробовали использовать полимер и ионик и всё тупило даже в тривиальных примерах. Поэтому запилили свой фреймворк, который по умолчанию рендерит лишь минимум, а остальное дорендеривает лишь по мере прокрутки. Давайте кооперироваться ;-)