Фреймворки кроссплатформенной разработки: ключевые факторы выбора стека
Маркетинг кроссплатформенной разработки продаёт красивую картинку: одна команда, один репозиторий, несколько платформ на выходе, бюджет ниже, чем при отдельных нативных приложениях.
Ратмир Чеботарев·Обновлено: 18 октября 2026 г.·11 мин

Звучит убедительно, пока не выясняется, что часть функций требует нативных модулей, сборка iOS привязана к macOS, а совместимость зависит от конкретных версий фреймворка и операционной системы.
Поэтому запрос «фреймворки кроссплатформенной разработки критерии выбора» лучше рассматривать как инженерную задачу, а не как поиск победителя в рейтинге. Нужно сопоставить цели продукта, платформы, которые действительно нужны пользователям, устройство UI, состав команды и ограничения сборочной инфраструктуры. Один репозиторий сам по себе не гарантирует ни одного релиза, ни одинакового поведения на устройствах, ни сокращения затрат.
Матрицы версий и поддержка целевых платформ
Первое, что стоит выяснить, это какие версии ОС фреймворк поддерживает и какие из них регулярно проверяет в CI. Эти понятия связаны, но не равны. Поддержка означает, что версия входит в заявленный диапазон совместимости. CI-матрица показывает, на каких конфигурациях команда проекта регулярно запускает автоматические проверки. Если версия ОС не попала в CI, это ещё не означает, что она исключена из поддержки.
Во Flutter 3.47 для Android указан диапазон API 24–37, а CI-тестирование охватывает API 24–36. Для iOS заявлена поддержка версий 15–27, при этом в CI проверяются iOS 18 и 26. Следовательно, iOS 16 и Android 25 поддерживаются, хотя в приведённый диапазон CI-тестирования не входят. Разница важна для планирования: такие версии нельзя объявлять неподдерживаемыми только потому, что они не перечислены среди регулярно проверяемых конфигураций. Но перед выпуском приложения с критичными функциями разумно отдельно проверить сценарии на целевых устройствах и свериться с текущей документацией.
Диапазон поддержки и набор CI-проверок отвечают на разные вопросы. Первый задаёт границы совместимости, второй показывает, что регулярно проверяет команда фреймворка.
У React Native на совместимость влияет не только версия мобильной ОС. Проект переходит на New Architecture, и это затрагивает нативные модули, которые приложение подключает помимо JavaScript-кода. Часть старых модулей может работать через слои совместимости, но при обновлении стека важно выяснить, поддерживает ли нужная библиотека актуальную архитектуру. Чем больше у приложения интеграций с устройством и внешними SDK, тем существеннее эта проверка. Апгрейд в таком случае может потребовать работы не только с самим React Native, но и с несколькими зависимостями, каждая из которых развивается в собственном темпе.
В Kotlin Multiplatform и Compose Multiplatform статус следует проверять отдельно для языка, общей логики и интерфейсного слоя. В описании экосистемы Android, iOS, Desktop JVM и Server-side JVM для Kotlin Multiplatform относятся к Stable, тогда как Kotlin/Wasm, watchOS и tvOS обозначены как Beta. У Compose Multiplatform Android, iOS и Desktop имеют статус Stable, а Web на Wasm остаётся Beta. Это не делает экспериментальные направления бесполезными, но меняет цену решения: нужно учитывать вероятность изменений API и готовность команды поддерживать отдельные обходные пути.
У.NET MAUI своя платформа поддержки: в рассматриваемом наборе требований Android начинается с API 21, iOS — с 11, macOS через Mac Catalyst — с 11, а Windows — с версии 10 1809 или новее. Для iOS есть и инфраструктурное условие: если код пишут в Visual Studio на Windows, для сборки понадобится подключённый Mac. Оно не исчезает оттого, что приложение кроссплатформенное, и влияет на устройство CI и распределение доступа к сборочной машине.
Минимальная версия ОС влияет не только на размер потенциальной аудитории. Она определяет, какие системные API доступны без дополнительных проверок и обходных решений. При этом повышение минимального порога может упростить реализацию новых функций, но исключить старые устройства. Решение стоит принимать вместе с продуктовой командой: какие версии нужны по требованиям рынка и пользователей, а какие поддерживаются по инерции.
Архитектурные модели UI и интеграция с нативным кодом
Кроссплатформенный стек не отменяет нативные API. Пуш-уведомления, биометрия, камера, платежи, фоновые задачи и отдельные системные сценарии рано или поздно приводят команду к платформенному коду или библиотеке, которая его содержит. Разница между фреймворками в том, как устроена эта граница и какой части приложения можно безопасно разделить реализацию.
React Native строит интерфейс через React-компоненты, связанные с нативными представлениями. Для доступа к возможностям платформы используются нативные модули, а для встраивания нативных элементов интерфейса есть отдельный механизм компонентов. Такой подход позволяет команде работать с привычной JS/TS-моделью, не отказываясь от системных возможностей. Но если в приложении много собственных модулей, потребуется разбираться и в нативной стороне: в Swift или Objective-C для iOS, Kotlin или Java для Android. При переходе на New Architecture нужно также оценить совместимость этих компонентов и план их обновления.
Flutter отрисовывает интерфейс собственным движком, а не собирает экран из стандартных нативных контролов. Это помогает сохранять согласованный вид на разных платформах и управлять анимациями внутри одного UI-слоя. Обратная сторона в том, что системное поведение не всегда получается получить автоматически: для нативных SDK нужны плагины или собственные платформенные интеграции. Если продукт опирается на стандартные формы и сложные системные сценарии, надо заранее оценить не только то, как экран будет выглядеть, но и как он будет взаимодействовать с платформой.
Kotlin Multiplatform позволяет делить код, сохраняя интерфейсы нативными: общую бизнес-логику можно писать на Kotlin, а экраны реализовывать на SwiftUI и Compose. Такой вариант подходит, когда важно не дублировать модели, правила обработки данных и другие общие части, но при этом сохранить привычные для платформ UI-инструменты. Компромисс очевиден: интерфейс приходится развивать в двух реализациях. Compose Multiplatform предлагает общий декларативный UI для нескольких платформ, однако его зрелость нужно оценивать по каждому целевому направлению, а не переносить статус Android или iOS на Web.
.NET MAUI использует Handlers для связи общего UI с нативными элементами платформ. Для команды, уже работающей с C# и.NET, это может быть естественным продолжением существующей архитектуры. Если же мобильная команда сформирована вокруг JavaScript или Kotlin, переход потребует не только освоения другого языка, но и пересмотра привычных инструментов, библиотек и практик.
Таким образом, сравнение фреймворков разработки под iOS и Android начинается с вопроса о том, какой UI нужен продукту. Если важна максимально единая визуальная система, логичен стек с общим интерфейсным слоем. Если интерфейс должен следовать платформенным паттернам и активно использовать системные компоненты, общий слой можно ограничить логикой и данными. Универсального правила здесь нет: решение зависит от дизайна, требуемого поведения и объёма нативных интеграций.
Зрелость экосистемы: смотреть не только на название фреймворка
Статус Stable или Beta полезен, но сам по себе не даёт полного ответа о готовности стека к конкретному продукту. Компонент может быть стабильным, а нужная библиотека — заброшенной или не готовой к последнему релизу. И наоборот, направление со статусом Beta может подойти для ограниченного внутреннего инструмента, если команда принимает связанные с ним риски.
Перед выбором полезно разложить экосистему на части:
- Сам фреймворк. Как часто выходят обновления, что меняется при переходе между версиями и насколько подробно описан процесс миграции.
- Нативные модули и плагины. Есть ли поддержка нужных функций устройства, кто сопровождает библиотеку и как она реагирует на обновления iOS и Android.
- Инструменты сборки и отладки. Можно ли воспроизводить ошибки локально и в CI, насколько удобна диагностика проблем на конкретной платформе.
- Навыки команды. Есть ли в команде люди, способные отлаживать нативную часть, или вся работа будет зависеть от одного специалиста.
- План выхода из зависимости. Что произойдёт, если важная библиотека перестанет поддерживаться или её API изменится.
| Стек | Общий подход к интерфейсу и коду | Что особенно важно оценить |
|---|---|---|
| Flutter | Собственный UI-слой и движок отрисовки | Поддержку нужных плагинов, работу с нативными SDK и различия между поддерживаемыми ОС и CI-матрицей |
| React Native | JavaScript/TypeScript-интерфейс с нативными компонентами | Совместимость модулей с New Architecture и доступность специалистов по нативной части |
| Kotlin Multiplatform | Общая логика, интерфейс может оставаться нативным | Какие модули будут общими и насколько удобно поддерживать UI на нескольких платформах |
| Compose Multiplatform | Общий декларативный UI для целевых платформ | Статус каждой нужной платформы, особенно Web-направления |
| .NET MAUI | Общий.NET-слой с Handlers для платформ | Связь с.NET-инфраструктурой и доступность Mac для сборки iOS |
У таблицы нет строки «лучший выбор», и это не недостаток сравнения. Один стек может быть удобнее для команды, у которой уже есть опыт в соответствующей экосистеме, и невыгоден для другой. Также нельзя выводить зрелость всего продукта из одного успешного демо: рабочий экран не проверяет обновление зависимостей, обработку ошибок, миграцию на новую архитектуру или сборку в чистом CI-окружении.
Среда сборки и ограничения операционных систем
Мобильный проект зависит от инструментов платформы даже тогда, когда большую часть кода пишут на общем языке. Для сборки iOS нужен macOS с Xcode. Это относится к React Native, Flutter, Kotlin Multiplatform и.NET MAUI: кроссплатформенный слой не заменяет инструментарий Apple. Если основная команда работает на Windows или Linux, проекту всё равно понадобится доступ к Mac для соответствующих этапов сборки и проверки.
Эту зависимость лучше предусмотреть в начале, а не после того, как разработка уже встроена в рабочий процесс. В CI потребуется организовать Mac-раннеры или другой доступный команде Mac-хост. Важно также решить, кто управляет обновлениями Xcode и сертификатами, как выдаётся доступ к машине и что происходит, если сборочная конфигурация отличается от локальной. Чем меньше ручных действий в релизном процессе, тем проще повторить сборку и найти причину ошибки.
У Android другая конфигурация инструментов, но наличие общей кодовой базы не отменяет проверки на самой платформе. Нужно следить за версиями SDK, поведением устройств и ограничениями фоновых сценариев. При этом поддерживаемый фреймворком диапазон ОС не гарантирует одинакового поведения на каждом производителе устройства. Часть различий приходит из операционной системы и аппаратной реализации, а часть связана с библиотеками приложения.
Для каждой целевой платформы полезно зафиксировать не только минимальную версию ОС, но и реальные сценарии, которые команда обязуется проверять: первый запуск, обновление приложения, разрешения, сетевые ошибки, работу в фоне и использование ключевых аппаратных возможностей. Такой набор не заменяет тестирование на устройствах, но помогает не спутать общую сборку с готовностью приложения к выпуску.
Производительность и стоимость команды
Сводить производительность к лозунгу «этот фреймворк быстрее» бессмысленно без одинакового сценария, устройств и методики измерения. Сопоставимых независимых замеров всех рассматриваемых стеков в одной конфигурации нет. Поэтому выбор лучше связывать с конкретными узкими местами: тяжёлой анимацией, отзывчивостью интерфейса, обработкой больших объёмов данных или количеством обращений к нативным API.
У Flutter собственный механизм отрисовки, что даёт команде большой контроль над визуальной частью. В React Native важную роль играют архитектура приложения, выбранные библиотеки и граница между JS- и нативным кодом. Kotlin Multiplatform позволяет делить логику, не меняя нативный UI..NET MAUI может лучше вписаться в инфраструктуру, где уже используются.NET-инструменты. Но эти наблюдения не заменяют прототип: на сложном экране слабое место может находиться не там, где его ожидают по описанию фреймворка.
Не менее важно считать стоимость сопровождения. Если UI общий, его легче развивать в одном месте, но платформенные особенности всё равно могут потребовать отдельных веток поведения. Если общая только бизнес-логика, интерфейсы придётся поддерживать раздельно, зато команде проще использовать нативные возможности. Экономия зависит от состава продукта, а не от процента кода, который удаётся вынести в общий модуль.
Цена кроссплатформенности определяется не количеством общих файлов, а тем, сколько платформенных различий команда готова сопровождать.
При оценке команды стоит учитывать не только найм разработчиков под выбранный язык. Важны специалисты, способные читать логи нативной сборки, обновлять SDK и диагностировать проблемы, которые не воспроизводятся в общем коде. Если такие знания есть у одного человека, это становится риском проекта. Если их нет вовсе, на обучение и адаптацию понадобится время, даже когда базовый UI уже собран.
Как выбор стека связан с требованиями продукта
Выбор технологического стека для мобильного приложения удобнее начинать не с названия фреймворка, а с нескольких решений о самом продукте. Какие платформы обязательны к запуску? Какие версии ОС нельзя исключить? Насколько интерфейс должен быть единым? Какие функции требуют нативных интеграций? Есть ли у команды опыт с языком и инфраструктурой выбранного стека?
Ответы часто сужают выбор быстрее, чем сравнительная таблица. Если команда сильна в JS/TS и продукту нужны iOS и Android, React Native может сократить путь до первой версии. Но набор сторонних модулей стоит проверить заранее, особенно при использовании New Architecture. Если важны сложный визуальный язык и единообразная отрисовка, Flutter может подойти лучше, при условии что критичные интеграции доступны или их реализацию можно поддерживать самостоятельно.
Когда задача состоит в повторном использовании логики при сохранении нативных интерфейсов, стоит рассмотреть Kotlin Multiplatform. Этот путь предполагает, что команда принимает две реализации UI и умеет поддерживать их согласованно. Если же нужен общий декларативный интерфейс, Compose Multiplatform требует отдельной оценки для каждой платформы, особенно тех направлений, где статус пока Beta. Для продукта, уже встроенного в.NET-экосистему,.NET MAUI может упростить организационную сторону, но условие с Mac для iOS-сборки остаётся.
До фиксации архитектуры полезно сделать небольшой вертикальный срез, а не только экран-прототип. В него стоит включить одну ключевую интеграцию, сборку для каждой целевой платформы, тестирование на минимально поддерживаемой ОС и прогон в CI. Такой срез показывает, где проходит реальная граница общего кода, какие библиотеки создают риск и насколько воспроизводим релизный процесс.
Универсального победителя нет. Для Flutter важны UI-модель, плагины и точное чтение матрицы версий. Для React Native существенны состояние нативных модулей и переход на New Architecture. Для Kotlin Multiplatform нужно решить, что именно будет общим, а для Compose Multiplatform отдельно проверить зрелость каждого целевого направления..NET MAUI имеет смысл оценивать в контексте имеющейся.NET-инфраструктуры и ограничений сборки iOS.
Главный критерий выбора прост: стек должен соответствовать не абстрактному обещанию переиспользования, а конкретным платформам, функциям и навыкам команды. Документация задаёт границы поддержки, CI показывает набор регулярно проверяемых конфигураций, а вертикальный срез выявляет то, чего не видно в таблице. Именно из этих трёх вещей и складывается решение, с которым можно жить после первого релиза.