Кроссплатформенная разработка — это создание программы, которая из одной общей кодовой базы работает на нескольких операционных системах или устройствах: Android и iOS, Windows, macOS и Linux, браузере. Общей обычно бывает не вся программа, а ее значимая часть — логика, иногда и интерфейс; платформенные детали все равно пишут отдельно.
Содержание
Ниже — словарь терминов, устройство основных подходов, их сравнение и порядок выбора под задачу.
Словарь: четыре термина, которые путают
| Термин | Что значит | Пример |
|---|---|---|
| Нативная разработка | Отдельное приложение под каждую ОС на ее «родном» стеке | Swift и SwiftUI для iOS, Kotlin и Jetpack Compose для Android |
| Кроссплатформенная разработка | Одна кодовая база, сборка под несколько ОС | Flutter, React Native, Kotlin Multiplatform, .NET MAUI |
| Гибридное приложение | Веб-интерфейс (HTML, CSS, JavaScript) внутри нативной оболочки с WebView | Ionic с Capacitor, Apache Cordova |
| Кроссплей в играх | Совместная игра или общий прогресс для игроков на разных платформах | Матч, где игроки с ПК и консоли в одном лобби |
Гибридный подход — частный случай кроссплатформенного: общий код есть, но интерфейс рисует встроенный браузерный движок. А в играх различают мультиплатформенность (игра выпущена на нескольких платформах) и кроссплей (игроки разных платформ играют вместе). Игра может быть мультиплатформенной без кроссплея.
Как код попадает на разные платформы
Главное различие подходов — что именно рисует интерфейс и во что превращается общий код. Упрощенная модель (детали зависят от версии фреймворка и платформы):
- Flutter. Код на Dart в релизной сборке компилируется заранее (AOT) в машинный код. Интерфейс фреймворк рисует сам своим движком, а не собирает из системных виджетов, поэтому выглядит одинаково на всех ОС.
- React Native. Код на JavaScript или TypeScript исполняется движком (по умолчанию Hermes), а интерфейс состоит из настоящих нативных компонентов платформы.
- Kotlin Multiplatform (KMP). Общая часть на Kotlin компилируется в байт-код JVM для Android и в нативный код для iOS. Интерфейс можно оставить нативным на каждой ОС или сделать общим на Compose Multiplatform.
- Electron. Настольное приложение — это веб-страница и Node.js внутри поставляемого вместе с программой движка Chromium. Так сделаны, например, Visual Studio Code и Slack.
- Веб и PWA. Приложение работает в браузере, установка не нужна; доступ к возможностям устройства ограничен тем, что разрешает браузер.
Языки с виртуальной машиной (Java, C#) и интерпретатором (Python) переносимы, пока на целевой ОС есть их среда выполнения; в играх ту же роль играют движки Unity и Unreal Engine.
Сравнение подходов
| Подход | Язык | Кто рисует интерфейс | Платформы | Когда брать | Ограничение |
|---|---|---|---|---|---|
| Нативный | Swift, Kotlin, C# и др. | Система | Одна на кодовую базу | Максимум возможностей ОС, сложная графика, строгие требования к отзывчивости | Две и больше команды и кодовые базы |
| Flutter | Dart | Собственный движок | Android, iOS, веб, Windows, macOS, Linux | Одинаковый дизайн везде, один интерфейс на все экраны | Новые API ОС — через плагины или свой платформенный код |
| React Native | JavaScript, TypeScript | Нативные компоненты | Android, iOS (другие — через сторонние проекты) | Команда знает React и веб-стек | Поведение компонентов может различаться между ОС |
| Kotlin Multiplatform | Kotlin | Нативный или Compose Multiplatform | Android, iOS, десктоп, веб, сервер | Общая бизнес-логика при нативном интерфейсе | Экосистема библиотек моложе, чем у нативного Android |
| .NET MAUI | C# | Нативные элементы через абстракцию | Android, iOS, Windows, macOS | Команда на .NET | Linux официально не поддерживается |
| Electron | JavaScript, HTML, CSS | Chromium | Windows, macOS, Linux | Десктоп силами веб-команды | Большой размер дистрибутива и расход памяти |
| Веб, PWA | JavaScript, TypeScript | Браузер | Любое устройство с браузером | Контент, формы, кабинеты | Ограниченный доступ к устройству, особенно на iOS |
Таблица описывает типичные сценарии, а не жесткие правила: на каждом стеке есть проекты, которые вышли за рамки своей строки.
Одна кодовая база — не значит «платформ не видно»
Даже в кроссплатформенном проекте часть кода зависит от ОС: пути к файлам, место для настроек, разрешения, уведомления. Минимальный пример на Dart (язык Flutter) — консольная программа выбирает каталог настроек по соглашениям разных ОС:
import 'dart:io';
// Где хранить настройки приложения: у каждой ОС свое соглашение.
String configDir(String app) {
final env = Platform.environment;
if (Platform.isWindows) {
return '${env['APPDATA']}\\$app';
}
if (Platform.isMacOS) {
return '${env['HOME']}/Library/Application Support/$app';
}
// Linux и другие Unix: стандарт XDG, по умолчанию ~/.config
final xdg = env['XDG_CONFIG_HOME'];
final base = (xdg != null && xdg.isNotEmpty) ? xdg : '${env['HOME']}/.config';
return '$base/$app';
}
void main() {
print('ОС: ${Platform.operatingSystem}');
print('Разделитель путей: ${Platform.pathSeparator}');
print('Настройки: ${configDir('notes')}');
}
Запуск dart run main.dart на Dart 3.13 в Linux-контейнере под пользователем root печатает:
ОС: linux
Разделитель путей: /
Настройки: /root/.config/notes
Если задать переменную XDG_CONFIG_HOME=/data/cfg, последняя строка станет Настройки: /data/cfg/notes. На macOS и Windows сработают другие ветки того же файла. Это и есть кроссплатформенный код: один исходник, а платформенные различия собраны в одном месте, а не разбросаны по программе.
Во Flutter для таких путей обычно берут готовый плагин (например, path_provider), который учитывает правила каждой ОС, включая песочницу iOS и Android. Пример выше показывает принцип, а не замену плагину.
Типичная ошибка: путь, собранный под одну ОС
Код, написанный и проверенный только на Windows, часто склеивает пути обратной косой чертой:
import 'dart:io';
void main() {
Directory('data').createSync();
File('data\\notes.txt').writeAsStringSync('привет');
for (final e in Directory('.').listSync()) {
print(e.path);
}
}
Результат в Linux — ошибки нет, но файл создан не в папке data, а рядом с ней, с обратной косой чертой прямо в имени:
./main.dart
./data\notes.txt
./data
Исправление — не склеивать разделитель вручную: взять Platform.pathSeparator или функцию join из пакета path:
import 'dart:io';
void main() {
final sep = Platform.pathSeparator;
Directory('data').createSync();
File('data${sep}notes.txt').writeAsStringSync('привет');
for (final e in Directory('data').listSync()) {
print(e.path);
}
}
Теперь файл лежит в нужной папке: программа печатает data/notes.txt. Такие ошибки не видны на машине разработчика, поэтому проект тестируют на каждой целевой ОС, обычно в CI.
Плюсы и минусы: без мифов
Что дает общий код. Одна реализация логики вместо двух-трех, общие исправления ошибок, одна команда. Выигрыш тем больше, чем больше доля общего кода.
Производительность. Утверждение «кроссплатформенное всегда медленнее нативного» — упрощение. Для типичных экранов со списками и формами разница часто незаметна. Она проявляется в тяжелой графике, обработке видео, долгом старте на слабых устройствах и в размере приложения: Flutter и Electron поставляют свой движок вместе с программой.
Доступ к новым функциям ОС. Когда Apple или Google выпускают новое API, нативные разработчики получают его сразу, а в кроссплатформенном проекте нужно ждать плагин или писать мост к платформенному коду самому.
Интерфейс. Flutter рисует одинаково везде, и это удобно для бренд-дизайна, но элементы могут отличаться от привычных системных. React Native и MAUI используют нативные элементы, зато их поведение иногда расходится между ОС.
Безопасность. Кроссплатформенность сама по себе не делает приложение уязвимее, но добавляет слой, который надо обновлять. Electron-приложение содержит свою копию Chromium: пока разработчик не выпустит версию на обновленном Electron, у пользователей остаются уязвимости, уже исправленные в Chrome. Для Electron отдельно важно держать включенными изоляцию контекста (contextIsolation) и не открывать Node.js удаленному контенту (nodeIntegration выключен). В мобильных фреймворках риск чаще в сторонних плагинах — их версии и права проверяют так же, как любую зависимость.
Что все равно делают под каждую платформу. Подпись и публикация в магазинах, разрешения, push-уведомления, встроенные покупки. Для сборки под iOS в любом фреймворке нужен Mac с Xcode.
Как выбрать подход
- Определите платформы. Только мобильные, только десктоп или все сразу — это отсекает половину вариантов из таблицы.
- Посмотрите на команду. Веб-разработчикам ближе React Native и Electron, Android-команде — KMP, .NET-команде — MAUI; Flutter потребует изучить Dart, но язык осваивается быстро, если знаете Java, Kotlin или TypeScript.
- Выпишите зависимости от устройства. Камера, Bluetooth, фоновая работа, платежи. Для каждой проверьте, есть ли поддерживаемый плагин.
- Решите, что важнее в интерфейсе: единый дизайн (Flutter) или привычные элементы каждой ОС (нативный UI, KMP с нативным UI, React Native).
- Соберите прототип одного сложного экрана на выбранном стеке и запустите на самом слабом целевом устройстве. Это дешевле, чем менять стек после релиза.
Если нужен предельный доступ к возможностям одной ОС, нативная разработка остается честным выбором.
Выводы
- Кроссплатформенная разработка — одна кодовая база для нескольких ОС; обычно общими бывают логика и часть интерфейса, а платформенные детали пишут отдельно.
- Подходы отличаются тем, кто рисует интерфейс: собственный движок (Flutter), нативные компоненты (React Native, MAUI), встроенный браузер (Electron, гибридные приложения).
- Разница в производительности с нативом зависит от задачи: для форм и списков она часто незаметна, для тяжелой графики и старта на слабых устройствах — заметна.
- Даже общий код содержит платформенные ветки (пути, настройки, разрешения), поэтому его тестируют на каждой целевой ОС.
- Выбор стека определяют платформы, навыки команды и зависимости от устройства, а проверяет его прототип сложного экрана.
Где применяется / связь с практикой
Освойте тему на практике
Кроссплатформенные стеки используют в мобильных приложениях сервисов, корпоративных системах и настольных инструментах. Если хотите освоить Flutter системно — от Dart и архитектуры приложения до публикации в магазины Android и iOS, — посмотрите курс «Flutter-разработчик». Чтобы сначала познакомиться с преподавателями и форматом, загляните на бесплатные открытые уроки Otus.
FAQ
Можно ли одним проектом покрыть мобильные приложения и сайт?
Технически да: Flutter и Kotlin Multiplatform умеют собирать веб-версию, а React Native — через проект React Native for Web. Но веб-сборка часто уступает обычному сайту в скорости загрузки и индексации, поэтому публичные страницы нередко делают отдельно.
Что стало с Xamarin?
Microsoft прекратила его поддержку в мае 2024 года; преемник — .NET MAUI. Проекты на Xamarin переводят на MAUI или на другой стек.
Java — это кроссплатформенный язык?
Программа на Java переносима между ОС, где установлена JVM, но это не решает задачу мобильного интерфейса под iOS. Кроссплатформенность языка и кроссплатформенность приложения с интерфейсом — разные вещи.



