company_banner

Архитектуры ReactNative, Xamarin, PhoneGap и Qt. Часть 2

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



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

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

    Qt


    Qt является одним из старейших кроссплатформенных фреймворков и используется очень широко для разработки embedded и десктопных приложений. Архитектура Qt позволяет портировать его в те операционные системы, которые имеют API для C++. И iOS, и Android (NDK), и Windows такой возможностью обладают, хотя и все со своими особенностями.


    Один из главных плюсов Qt — собственная эффективная система отрисовки пользовательского интерфейса либо на базе растрового движка (например, CoreGraphics в iOS), либо на базе Open GL (ES). Именно это и делает фреймворк портируемым. То есть в Qt используются свои механизмы отрисовки UI — приложение будет выглядеть нативным настолько, насколько вы его сами стилизуете.



    Как видим, на iOS используются стандартные модули CoreGraphics и UIKit для отрисовки пользовательского интерфейса. В Android ситуация чуть посложнее, так как Qt использует механизмы NDK для отрисовки UI, а для доступа к Java API и управления приложением используется уже знакомый нам мост JNI. Также в iOS и Android может использоваться Open GL ES для отрисовки QML или работы с 3D.


    В Windows имеется прямой доступ к C++ API и все работало бы отлично, если бы не необходимость использовать конвертацию вызовов Open GL ES в вызовы DirectX (растровая отрисовка не удовлетворяет по производительности, а Open GL ES нет в Windows UWP). В этом помогает библиотека ANGLE.


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

    В целом Qt можно было бы рекомендовать как вещь в себе — только готовые модули самого фреймворка плюс платформонезависимые библиотеки на C++. Но в реальных проектах его использовать будет очень непросто — неродной UI, отсутствуют сторонние компоненты (только библиотеки “из коробки”), возникают сложности при сборке и отладке приложения, а также при доступе к нативной функциональности. Из плюсов — высокая производительность кода на C++.



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

    Xamarin


    Xamarin сейчас доступен в open source и появился в качестве развития проекта Mono, открытой реализации инфраструктуры .NET для Unix-систем. Изначально Mono поддерживался компанией Novell и позволял запускать .NET-приложения в Linux и других открытых ОС.


    Для взаимодействия с родными (для C) интерфейсами операционных систем в Mono используется механизм P/Invoke. На основе Mono были созданы фреймворки MonoTouch и MonoDroid, которые затем переименовали в Xamarin.iOS и Xamarin.Android, и теперь вместе называют “классическим Xamarin” (Xamarin Classic).


    Классический Xamarin предоставляет полный доступ к нативным API, то есть можно создавать нативные приложения iOS/Android с помощью C# без единой строчки на Objective C и Java. Нативные библиотеки подключаются через механизм байндинга (Native Library Binding). Взаимодействие с ОС происходит через мост и механизм оберток (wrappers), однако нет необходимости сериализовать данные, так как осуществляется автоматический маршалинг и есть возможность прямой передачи ссылок между средами Mono Managed и Native. Можно также использовать большое количество .NET-библиотек из NuGet.



    Инфраструктура .NET/Mono предполагает использование JIT по аналогии с Java, когда приложение упаковывается в промежуточный байт-код и уже потом компилируется во время исполнения. Но из-за ограничений iOS нет возможности использовать JIT, и поэтому байт-код Xamarin.iOS-приложений компилируется в нативный бинарный и статически линкуется вместе с библиотеками. Такая компиляция называется AOT (Ahead Of Time) и является обязательной в Xamarin.iOS. В Xamarin.Android же помимо AOT доступен и режим JIT, когда виртуальное окружение Mono работает параллельно с Dalvik/ART.


    Как видим, общая база кода между платформами ограничивается бизнес-логикой и механизмами работы с данными. К сожалению, UI и платформенную функциональность приходится реализовывать отдельно для каждой платформы. В результате шарить можно не более 30%-40% от общей базы кода мобильных приложений. Для достижения большего результата необходимо использовать Xamarin.Forms, о котором мы расскажем в Главе 3.5.


    Ключевым преимуществом классического Xamarin является использование языка C# для всего кода и, как следствие, разработчиков, которые уже хорошо знакомы с .NET. Также обязательным является хорошее знание и понимание механизмов iOS/Android, их классовых моделей, архитектур, жизненных циклов объектов и умение читать примеры на Objective C и Java.


    Производительность C#-кода сопоставима с производительностью нативного кода в iOS/Android, но при взаимодействии с ОС используется мост, который может замедлять приложение при неэффективном использовании.

    Классический Xamarin является достаточно зрелым решением и обеспечивает максимально близкий к нативному опыт разработки для C#-программистов и использованием привычных инструментов вроде Visual Studio.



    Итак, если стоит задача реализовать полностью нативное приложение и при этом имеются опытные C#-разработчики, то Xamarin может стать хорошим выбором для широкого спектра задач, как больших (более 40 экранов), так и маленьких (до 10 экранов).

    Xamarin.Forms


    Если у вас стоит цель максимизировать общую базу кода, то классический Xamarin здесь явно проигрывает всем остальным фреймворкам (PhoneGap, ReactNative, Qt и их аналогам). Это понимали и в самом Xamarin, поэтому выпустили решение, позволяющее использовать единое описание UI и простые механизмы доступа к платформенным фичам — Xamarin.Forms.


    Библиотека Xamarin.Forms работает поверх описанного ранее классического Xamarin и фактически предоставляет механизмы виртуализации пользовательского интерфейса и дополнительную инфраструктуру.




    Для того, чтобы лучше понять, как работает XF, давайте рассмотрим простую кнопку. Одним из базовых механизмов являются рендереры (renderers), благодаря которым при отображении кнопки Xamarin.Forms фактически на экран добавляется нативный контрол, а свойства XF-кнопки динамически пробрасываются в свойства нативной кнопки на каждой платформе. В ReactNative используются похожие механизмы.



    Общая (shared) часть на Xamarin.Forms обычно реализуется в виде библиотеки (Portable/PCL или .NET Standard) и имеет доступ к базе компонентов в NuGet. Платформенная часть реализуется на базе Xamarin Classic и имеет полный доступ к нативному API, а также возможность подключения сторонних библиотек. При этом общий процент кода между платформами обычно доходит до 85%. Также Xamarin.Forms можно использовать в режиме Embedded для создания отдельных экранов и View внутри приложений на классическом Xamarin.iOS и Xamarin.Android.



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

    Заключение


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


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

    При выборе фреймворка стоит учитывать не только язык программирования, но и необходимый уровень знаний целевых операционных систем (iOS, Android, Windows), а также опираться на опыт вашей команды разработчиков. Например, при использовании PhoneGap можно обойтись поверхностными знаниями ОС, если не требуется вручную реализовать платформенную функциональность. А для Xamarin Classic придется стать экспертом в iOS и/или Android.


    В качестве итога давайте соберем все рекомендации по выбору фреймворков в одном месте:


    • PhoneGap — если вам необходимо быстро сделать простое приложение или прототип и в команде есть опыт разработки одностраничных веб-приложений (HTML, JavaScript, CSS). В большинстве случаев можно обойтись готовыми плагинами для нативной функциональности. Из минусов — неродной интерфейс с частыми подергиваниями и залипаниями и непростой доступ к нативной части. Процент разделяемого кода — до 95%.
    • ReactNative — отлично подойдет для опытных JavaScript-разработчиков и команд, но потребует достаточно хорошего знания iOS Objective C API и Android Java API. Приложения выглядят и работают нативно, но также стоит учитывать юность фреймворка. Процент разделяемого кода — до 90%.
    • Xamarin Classic — если у вас есть опытные C#-разработчики, то им потребуется глубоко освоить iOS и Android. Приложения будут полностью нативными, хотя и написаны на C#. Объем общей базы кода в редких случаях превышает 40%.
    • Xamarin.Forms — подойдет опытным C#-разработчикам, особенно со знанием XAML. Для приложений с простым интерфейсом (стандартные контролы или готовые компоненты) не потребуется глубоких знаний iOS/Android/Windows. Процент разделяемого кода — до 90%.
    • Qt — этот фреймворк можно рекомендовать только в случае, если у вас уже есть существующее приложение (например, embedded) и его необходимо запустить на iOS/Android. Высокие требования к квалификации разработчиков, непростой доступ к нативной функциональности и неродной UI являются заметными минусами фреймворка. Процент разделяемого кода может доходить до 95%.


    P.s. Выражаю благодарность Роману Здебскому и Ахмеду Шериеву за ценные дополнения, а также Елизавете Швец и Марии Горелкиной за помощь с публикацией.
    Полную версию руководства вы можете найти на 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.

    Оставайтесь на связи и задавайте свои вопросы в комментариях!
    Microsoft 387,47
    Microsoft — мировой лидер в области ПО и ИТ-услуг
    Поделиться публикацией
    Комментарии 17
    • +2
      В целом Qt можно было бы рекомендовать как вещь в себе — только готовые модули самого фреймворка плюс платформонезависимые библиотеки на C++. Но в реальных проектах его использовать будет очень непросто — неродной UI, отсутствуют сторонние компоненты (только библиотеки “из коробки”), возникают сложности при сборке и отладке приложения, а также при доступе к нативной функциональности. Из плюсов — высокая производительность кода на C++.
      Не, ну это несерьезно:
      • Неродной UI — получаем тот же Look and Feel, но быстрее! На винде Alien-виджеты работают намного быстрее честных виндовых окошек.
      • отсутствуют сторонние компоненты (только библиотеки “из коробки”) — в Qt из коробки есть не только лишь все… Серьезно, Qt обычно только за это и ругают, что он тяжелый, потому как там реально все есть.
      • возникают сложности при сборке и отладке приложения — какие? Я с одной машины могу под все платформы Qt собрать, да еще и свое мобильное приложение под Desktop'ом покрутить в окошке
      • сложности также при доступе к нативной функциональности — тут да, однако C++ могучий, с ним до куда угодно можно дотянуться, без всяких PInvoke'ов

      Qt очень хорош, хотя и действительно нужна квалификация разрабов.
      • +1
        Все зависит от специфики проекта, конечно. Из моего опыта работы с Qt (более 5 лет для desktop, maemo, symbian, windows mobile и embedded):
        Неродной UI — получаем тот же Look and Feel, но быстрее! На винде Alien-виджеты работают намного быстрее честных виндовых окошек.


        Так UI все равно не родной, а для получения нужного Look'n'Feel (стандартные анимации и поведение элементов) потеть приходится очень усердно для каждой платформы.

        отсутствуют сторонние компоненты (только библиотеки “из коробки”) — в Qt из коробки есть не только лишь все… Серьезно, Qt обычно только за это и ругают, что он тяжелый, потому как там реально все есть.


        Современный mobile это в первую очередь работа со сторонними библиотеками ;) В Qt очень ограниченный доступ к нативке, только через свои обертки.

        возникают сложности при сборке и отладке приложения — какие? Я с одной машины могу под все платформы Qt собрать, да еще и свое мобильное приложение под Desktop'ом покрутить в окошке


        Отладка и тестирование реальных приложений на реальных устройствах с полной функциональностью. Десктоп-версия далеко не весь функционал позволяет посмотреть, но судя по всему вы пока с этим не сталкивались.

        сложности также при доступе к нативной функциональности — тут да, однако C++ могучий, с ним до куда угодно можно дотянуться, без всяких PInvoke'ов


        К Java и Objective C дотянуться ой как непросто ;) В реальных проектах, конечно же.

        Но это все мое IMHO, основанное на моем опыте работы с большим количеством реальных мобильных проектов.
        • 0
          Современный mobile это в первую очередь работа со сторонними библиотеками ;) В Qt очень ограниченный доступ к нативке, только через свои обертки.


          Можно пояснить, к каким сторонним библиотекам я не могу динамически слинковаться или сделать dlopen с extern c? Для этого необязательно совсем использовать Qt Interface, хотя и можно. Разница вся будет только в том, что в первом случае всю работу по работе с библиотеками делает сам пользователь, а во втором — Qt, зная свои метаданные и интерфейс, к которому, благодаря метаданным, QPlugin или другой модуль будет делать qobject_cast.

          Ну, или я все не так понял?
          • 0
            Серьезно, сейчас большинство проектов используют те или иные SDK (сложные контролы, просмотр файлов, свои карты, оплата онлайн, навигация, работа с Push, сбор пользовательских метрик и крешей), которые теоретически можно подключить к Qt, но быстрее может оказаться написать нативное приложение :)
        • Блог компании майкрософт же — понятно дело тут будут рекламировать не Qt.
          • +1
            Да ладно вам ;) Я большой фанат Qt и очень любил работать с ним, однако для iOS/Android/Windows UWP он просто не подходит в реальных проектах
            • Да и я как бе шарпист и за мелкомягких т. е. aps/wpf/xmarin/uwp. Просто не люблю когда такие сравнения проводят просто ряди рекламы своего продукта.
              • 0
                Вы о чем? Везде ищите заговор зеленых массонов с планеты Нибиру?

                Продуктом нашей компании Binwell являются услуги по заказной разработке ПО с использованием кроссплатформенных инструментов (сейчас Xamarin). Эти услуги мы и рекламируем такием ветиеватым образом — за годы работы дико достали невежды кричащие «ненативно» и не понимающие как что работает. В России с низкой общей культурой промышленной разработки ПО это стало просто каким-то звиздецом.

                Если вы считаете, что я необъективно оценил возможности Qt (имея опыт, сертификаты и статусы), то готов принять вашу позицию и внести нужные правки в статью или руководство.
        • 0
          Спасибо за статьи! При всей любви к Xamarin, стал все чаще заглядываться на React Native. В продакшн пока все равно его страшно правда. Хотя для веба в последнее время всё на Vue/Nuxt, хорошо было бы юзать Weex, но он там вовсе в зачаточном состоянии.

          Так что альтернатив Xamarin (скорее даже Forms) всё еще не вижу… нативно, в основе достаточно примитивно, и вполне продуктивно.
          • +2
            Фигня этот Реакт Натив.

            Изначально в компании решили сэкономить, поэтому было принято взять React Native, чтобы написать одно приложение под все устройства, и вообще все красиво и ровно. Приложение достаточно большое и сложное, которое подтягивало куча всего.

            В итоге, через год борьбы с тем, что «в общем, все работает», но частности на каких-то пограничных ситуациях и весьма сомнительных китайских девайсах, все отваливается и не работает, либо адски тупит.

            Мы в пошли на встречу нашим кастомерам и мольбам технической поддержки, и переписали под дваву и свифт для каждой платформы. Косяки определенные остались, конечно, но работает в разы стабильнее.
            • 0
              Вот и я того же опасаюсь. С хамарином я публиковал (Forms-)приложения с реально небольшими переделками и в аппстор, и в гуглплэй (причем контролы все нативные). Стабильность росла с уровнем выпрямления моих рук по мере нарастания опыта с Хамарин и его, кстати, стабилизацией тоже. А глядя на тот как реакт ломает обратную совместимость с каждой версией… пока что «да ну». Хотя JS/ES6 я предпочитаю шарпу, но тут не тот случай.
          • 0
            Спасибо за обзор!

            Такой вопрос.

            Есть ли на Qt проработанная, законченная, известная архитектурная модель построения приложения под Android (и, возможно, iOS), при которой возможно было бы запускать приложение одновременно как с пользовательским интерфейсом (Активити), так без него (Сервис)?

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

            Понятно, что можно сделать приложение отдельно с пользовательским интерфейсом, а отдельно — как сервис. Т.е. два отдельных приложения. А, вот, чтобы это всё в одном приложении жило, есть ли какие методики под Android на Qt (и, возможно, iOS)?

            Может, знаете какие-нибудь ссылки на открытые проекты с похожей архитектурой, или на описание её в блогах гуру Qt?
            • 0
              По Qt могу только дать рекомендацию — либо используйте только Qt как вещь в себе (например, для простых игр или небольших развлекательных приложений), либо не используйте его на iOS/Android/Windows UWP. Все остальное — скользкий и нестандартный путь, по которому если кто и ходит, то о своих результатах пишет большое количество негатива на форумах. Просто нет ценной информации в публичном доступе, особенно по вопросам такого уровня как архитектуры и паттерны. И причина проста — никто не ходит этим путем. Любой фреймворк это всего лишь инструмент. Для разного класса задач подходят разные инструменты.

              Вообще тема Qt на iOS и Android очень очень очень плохо раскрыта. При подготовке обзора пришлось ковыряться в исходниках Qt, чтобы лучше понять как оно работает на каждой платформе.
            • 0
              Мне кажется в этой серии статей Xamarin немного превознесён над остальными. Надеюсь мой опыт поможет сомневающимся. Я долго искал кроссплатформенный инструмент разработки моб. приложений для команды, прочитал много аналитики и работал с Cordova, Xamarin.Forms, ReactNative длительное время. В итоге сделал выбор в пользу последнего.
              В Cordova слишком много кейсов, при которых начинаются тормоза, тяжело выстроить правильную архитектуру приложения.
              В Xamarin.Forms очень много времени отнимали непредвиденные баги контролов, баги компиляции, проблемы с библиотеками. Даже имея почти год опыта использования Xamarin.Forms периодически наталкивался на странные ошибки, связанные с ошибками в Mono, на решение которых уходила уйма времени. Другие минусы: долгая компиляция, неочевидное поведение контейнеров, работа с изображениями, многословность описания интерфейса. Из плюсов — действительно почти нативная скорость, строгая архитектура приложения, хорошие возможности к абстрагированию кода благодаря C#.
              Скорость разработки на ReactNative гораздо выше чем на Xamarin.Forms, компилировать не надо, можно использовать Hot Reloading, который обновляет интерфейс сразу после изменения кода, без перезагрузки страницы. Интерфейсы описываются коротко и интуитивно понятно. В целом интерфейс описывается как в вебе, с упором на flexbox. Контроль за состоянием приложения гораздо лучше чем в Xamarin, особенно с использованием Redux/Mobx, следовательно и отладка гораздо проще. Минусы: слишком много библиотек решающих одну и ту же проблему, иногда тяжело выбрать, а если нет нужной, придётся писать свою на нативных языках под каждую платформу(хотя мне ещё не приходилось, всегда находил нужную). Кроме того, большие списки иногда тормозят, но в целом производительность примерно как у Xamarin, в каких-то тестах он даже обходит Swift, но не думаю что можно им слепо верить.
              В целом Xamarin.Forms и ReactNative можно использовать в продакшене и для больших приложений. Xamarin имеет хорошую задумку, но до сих пор, спустя столько времени, слишком сырой. ReactNative несмотря на версию 0.49 гораздо стабильнее чем Xamarin и практически во всём выигрывает.
              • +1
                Полностью согласен по поводу производительности программистов на ReactNative — когда все созреет, то будет быстро. Но и по Xamarin.Forms тоже есть подходы, когда уникального кода (отдельные экраны и фоновые сервисы, работа с данными) получается немного и как следствие основное время уходит на UI.

                Скоро выложим пример лаконичного кода на XF вместе с новым руководством ;)
              • 0
                Добавлю немного своих пару копеек… Очень давно занимаюсь андройдом (с версии 1.6), с Qt работал в общей сложности примерно 2 года. По этой причине ясень пень Qt на андройд пилить глупо, т.к. андройд сам по себе куда приятнее и удобнее в плане имеющихся инструментов. На С# тоже приходлось работать, с WPF.

                На Qt приходилось всякое делать, начиная от приложения с прорисовкой большой 2D сцены на OpenGL с полупрозрачными виджетами поверх, полностью кастомно отрисованный, заканчивая последними опытами по поднятию с колен говнокод проекта… У Qt есть множество проблем в Ui части, например большинство вьюх вообще не живут с большими объемами данных. Как раз при поднятии с колен пришлось например полностью заимплементить логику по сортировке с сохранением стейтов айтемов в QTreeView… т.к. нативная для Qt QProxySortModel при количестве айтемов с 3мя и более нулями тупо умирает вместо со всей вьюхой унося с собой на дно весь Main Thread. Радости это приносит мало, по большей части боль в области соприкасающейся с плоскими поверхностями при работе…
                • 0
                  Со своей стороны хочу добавить про то, что сейчас Qt — это больше QML, нежели C++. Конечно, с мобильными платформами все посложнее будет, но ситуация постепенно улучшается. Я все же надеюсь на появление библиотек нормального качества для работы с API мобильных платформ. А то прокидывать, например, все через JNI — то еще удовольствие.

                  Что мне нравится в QML, так это внятная декларативность. А в случае, когда декларативности не хватает — можешь писать на JavaScript. И то и другое может освоить даже дизайнер. Таким образом, можно иметь одного опытного чувака, который будет работать на C++ glue и предоставлять все нужное для QML. А в QML могут работать люди, которые знакомы с JS, или даже дизайнеры. Например подкрутить анимации или накидать экран — реально просто.

                  На счет подгона под Look&Feel платформы — все так. Это может быть та еще боль и страдания. Один скролл чего стоит.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое