Перевод нативного приложения на Flutter или React Native
Продвинутое3 минРедакция Innovialabs
Коротко
Чаще всего безопаснее постепенная миграция: новые экраны пишутся на Flutter или React Native внутри нативного приложения, авторизацией и данными владеет один слой, а релизы идут как обычно; полное переписывание оправдано для небольших или сильно устаревших приложений.
Два пути и как выбрать
Есть два основных способа перевести нативное приложение на кросс-платформу:
- Полное переписывание — новое приложение пишется с нуля и заменяет старое одним релизом.
- Постепенная миграция (add-to-app, brownfield) — Flutter или React Native встраиваются в существующее нативное приложение, и экраны переводятся по одному.
| Критерий | Полное переписывание | Постепенная миграция |
|---|---|---|
| Риск для текущих пользователей | Высокий: всё меняется сразу | Ниже: изменения порциями |
| Релизы во время работ | Старое приложение замораживается или ведётся параллельно | Идут как обычно |
| Сложность архитектуры | Ниже: один стек | Выше: два стека одновременно |
| Размер сборки в переходный период | Обычный | Больше: два рантайма |
| Подходит для | Небольших приложений, устаревшего кода | Крупных живых продуктов |
Если приложение небольшое, а код плохо поддерживается, переписать бывает проще. Если продукт большой, приносит деньги и активно развивается, почти всегда разумнее идти постепенно.
Как устроена постепенная миграция
- Flutter поддерживает режим add-to-app: Flutter-модуль подключается к iOS- и Android-проектам, экраны открываются через
FlutterViewControllerиFlutterActivityилиFlutterFragment. Движок лучше прогревать заранее и переиспользовать, иначе первый переход на Flutter-экран будет заметно медленнее. - React Native встраивается в существующее приложение как набор view, которые нативный код открывает как обычные экраны.
Порядок работ:
- Выделите границы: какие экраны и сценарии переносятся первыми. Хорошие кандидаты — новые функции и изолированные разделы (профиль, настройки, каталог).
- Настройте сборку и CI так, чтобы модуль собирался вместе с нативными проектами.
- Определите контракт обмена между нативной и кросс-платформенной частью: навигация, события, данные.
- Переносите раздел за разделом, удаляя нативный код после каждого переноса.
- Когда нативной остаётся только оболочка, решите, переходить ли на полностью кросс-платформенный проект.
Как не останавливать релизы
- Каждый перенесённый экран прячьте за feature flag и раскатывайте постепенно.
- Сохраняйте тот же bundle ID и подпись приложения: пользователи должны получить обычное обновление, а не новое приложение.
- Держите старую реализацию, пока новая не подтвердит стабильность по крэшам и метрикам.
- Планируйте миграцию так, чтобы в одном релизе менялась ограниченная часть продукта.
Общая авторизация и данные
Самая частая проблема — две части приложения, которые по-разному понимают, кто пользователь.
- Один владелец сессии. Токены хранятся в одном месте (Keychain, Keystore), и обновляет их один слой. Вторая часть получает токен через мост, а не ведёт свою логику refresh.
- Мост с явным контрактом. Во Flutter — platform channels; для типизированных интерфейсов удобен генератор Pigeon. В React Native — нативные модули. Описывайте контракт как API: методы, типы, ошибки.
- Один источник данных. Если нативная часть работает с локальной базой, кросс-платформенная должна читать её через мост или общий API, а не создавать свою копию.
- События. Выход из аккаунта, смена языка, обновление профиля должны доходить до обеих частей.
// Flutter: запрос токена у нативной части
const channel = MethodChannel('app/auth');
final token = await channel.invokeMethod<String>('getAccessToken');
Риски
- Производительность переходов между нативными и кросс-платформенными экранами.
- Рост размера сборки на переходный период.
- Два набора компетенций в команде одновременно.
- Нативные зависимости: SDK, у которых нет плагина или модуля, придётся оборачивать вручную.
- Затянувшаяся миграция, когда половина приложения навсегда остаётся на двух стеках.
Когда миграция не стоит усилий
- Нативные команды работают хорошо, а проблемы продукта не связаны с технологией.
- Приложение глубоко завязано на платформенные функции: сложная работа с камерой, AR, фоновые сервисы, виджеты.
- Нет ресурсов довести миграцию до конца — полумиграция дороже любого из чистых вариантов.
- Причина миграции — мода, а не измеримые цели: скорость выпуска функций, единая команда, общий код.