Кроссплатформенное мобильное приложение выбирают ради одного: одна кодовая база вместо двух, одна команда, один цикл выпуска. На старте это работает, и спорить тут не с чем. Разговор, которого обычно не происходит, — про то, что будет с этим приложением через два года, когда проект давно сдан, а продукт продолжает жить в телефонах людей.
Дальше — о том, что происходит с приложением на горизонте двух лет: обновления операционных систем, требования магазинов, зависимости, устройства, которые перестают поддерживаться. Труд мы меряем часами и людьми: часы — это объём работ, а не цена, и именно их вам придётся где-то взять — в своей команде, у подрядчика или ни у кого.
И сразу оговорка, без которой разговор превращается в рекламу: мы не утверждаем, что кроссплатформенный подход лучше нативного или наоборот. Условия бывают разные, и ниже мы каждый раз называем условие, при котором ответ меняется.
Сайт, который не трогают, продолжает открываться. С приложением не так, и это главное, что стоит принять до первого релиза. У него есть внешняя среда, которая меняется по чужому расписанию: операционные системы, правила магазинов, библиотеки, сертификаты подписи, сервисы уведомлений и карт. Любой из этих пунктов может потребовать работы в месяц, когда вы не планировали никаких изменений.
Мы формулируем это жёстко, зато точно: библиотеки стареют независимо от того, меняется продукт или нет, и уязвимости появляются сами собой. Продукт без сопровождения через пару лет становится небезопасным, даже если в него не вносили правок.
Отсюда первый практический вывод. Решение «поддержку пока не берём, продукт же работает» — это не экономия и не отсрочка. Это перенос работы на тот месяц, когда её придётся делать срочно и в объёме, который вы уже не выбираете.
Новые версии iOS и Android выходят ежегодно, и у каждой свой список изменений, которые задевают работающее приложение: поведение разрешений, фоновые задачи, оформление системных элементов, работа с файлами и уведомлениями. Часть изменений ломает сценарий молча: приложение собирается и запускается, но разрешение больше не спрашивается, и функция перестаёт работать у новых пользователей.
Отдельно — требование площадок собирать приложение с актуальным набором инструментов. Оно объявляется заранее и исполняется по календарю магазина: в какой-то момент сборку на устаревшем наборе перестают принимать. Для давно не обновлявшегося приложения это выглядит как внезапная блокировка, хотя предупреждение было за год.
Что из этого следует для плана. Каждый год, вслед за выходом новых версий систем, у приложения возникает всплеск работ, не связанный с развитием: проверка на новой системе, правка того, что разъехалось, пересборка и релиз. Это не авария, а сезон, и закладывать его нужно заранее — как отчётный период. Сроков этого сезона в неделях мы не замеряли, он зависит от того, сколько в приложении сценариев, завязанных на систему.
Вторая внешняя сила — правила площадок. За последние годы они заметно сдвинулись в сторону прозрачности: приложение обязано заявить, какие данные собирает, какие из них связаны с личностью человека, какие используются для отслеживания, передаются ли они третьим сторонам и можно ли попросить их удалить. Заявленное должно совпадать с тем, что приложение делает на самом деле.
Это работа не на стороне приложения, а на стороне всей системы: когда вы добавляете новый сервис аналитики или новый способ оплаты, состав собираемых данных меняется, а значит, меняется и декларация. Пропустить обновление декларации легко — её заполняют один раз при первой публикации и потом про неё забывают, пока на модерации не прилетит замечание.
Туда же — требования к возрастному цензу, к описанию покупок внутри приложения, к политике конфиденциальности, к тому, как запрашиваются согласия. Каждое изменение правил — часы работы, которые не превращаются ни в одну новую функцию.

Приложение собрано не только из вашего кода. Под ним фреймворк, рядом чужие библиотеки: сеть, хранение данных на устройстве, графики, карты, аналитика, уведомления, платежи. У каждой свой автор и свой темп обновлений, с вами не согласованный.
Пока обновления делают регулярно, каждое занимает немного: подняли версии, прогнали сборку, проверили сценарии, выпустили. Пропущенные два года ведут себя иначе. Версии расходятся так, что обновить одну библиотеку нельзя без обновления соседней; часть библиотек за это время перестала поддерживаться и замены требует целиком; а переход на новую мажорную версию фреймворка превращается в отдельный проект с переписыванием экранов. Разница не в процентах: вместо потока мелких задач вы получаете один большой, который нельзя ни отложить, ни разбить.
Отдельный класс риска — библиотека, которую автор забросил. Для ключевых функций это стоит проверять заранее: когда был последний выпуск, сколько людей её сопровождает, есть ли у неё живая альтернатива. Для того, без чего продукт не работает, разумнее опираться на то, что поддерживается самим фреймворком, даже если на старте это дороже в разработке. Это наше рабочее правило, а не замер по проектам: цифр, во что обошлась замена брошенной библиотеки, мы не фиксировали.
У каждого приложения есть нижняя граница: минимальная версия системы, ниже которой оно не устанавливается. Границу определяют по статистике вашей аудитории, а не из общих соображений, и фиксируют письменно при старте — чтобы через полтора года не спорить, почему приложение не ставится на телефон собственника.
Через два года граница неизбежно поползёт вверх: поддерживать очень старые версии дорого, а доля людей на них падает. Решение поднять минимальную версию — это осознанный отказ от части аудитории, и принимать его должен владелец продукта, а не разработчик между делом. Поэтому вопрос «сколько процентов пользователей мы отсечём и кто они» задают до работ, а не после.
Вторая половина темы — производительность. Приложение замедляется не само, а от роста данных: список, который летал на двухстах записях, спотыкается на двух тысячах, изображений становится в десять раз больше, локальная база растёт вместе со сроком жизни установки. На флагмане разработчика этого не видно совсем, а на недорогом телефоне трёхлетней давности видно сразу — и именно там находится заметная часть аудитории. Проверка на реальном парке устройств, а не в эмуляторе, — регулярная работа, а не разовая настройка перед релизом.

Самый честный способ показать это — посмотреть на собственный проект. Приложение сети ресторанов «Епонский Городовой» мы спроектировали и разработали для iOS, карточка проекта опубликована у нас в кейсах. Сегодня его страница в App Store показывает последнюю версию 1.1.3 от 23 мая 2022 года, оценку 2,1 из 5 при шестидесяти оценках и отзывы 2024 и 2025 годов с одной и той же жалобой: не получается войти по номеру телефона.
Что здесь важно для расчёта. Почему выпуск версий прекратился, карточка не объясняет, и мы этого не утверждаем: это решение владельца продукта, и в кейсе оно не зафиксировано. Зато видно другое — последовательность, которая повторяется и у чужих приложений. Сначала перестают выходить обновления. Потом ломается не функция, которую кто-то менял, а та, что зависит от внешнего сервиса: вход по звонку или по сообщению, карты, оплата. Потом это попадает в отзывы, оценка опускается, и карточка в магазине начинает работать против компании, которая этот продукт заказывала.
Обратите внимание на сроки: между последним обновлением и последней жалобой прошло три года. Всё это время приложение оставалось в магазине, его можно было установить, и люди его устанавливали.
Приложение академии EDPRO мы собрали на Flutter, и в кейсе отдельно отмечено, что кроссплатформенный стек ускорил выпуск версий для обеих платформ. Но для темы этой статьи важнее строка из отзыва заказчика: продукт без проблем взяли к себе, как и планировали, и продолжают развивать дальше. В том же отзыве кроссплатформенность названа плюсом именно по причине поддерживаемости.
Это и есть второй возможный финал двухлетнего горизонта. Приложение не обязано оставаться у подрядчика: его можно передать своей команде, если оно собрано на распространённом стеке, снабжено документацией и не обвешано самописными решениями там, где есть штатные. Условие, при котором это работает, стоит назвать прямо: у заказчика есть кому его взять. Если своей команды нет и не предвидится, передача ничего не решает — тогда вопрос не «кому отдать», а «с кем договориться о регулярном объёме часов».
Перейдём к мере. Поддержка живого приложения — это не «иногда позвать разработчика». Это несколько ролей, и они нужны одновременно, хотя и не на полную загрузку: разработчик, который ведёт сборку и зависимости; тот, кто проверяет сценарии на парке устройств; тот, кто отвечает за выпуск — подготовку материалов карточки, подачу, ответы модерации; и человек на стороне заказчика, который решает, что в этот релиз входит, а что ждёт.
Последняя роль чаще всего и оказывается пустой. Без неё поток задач превращается в список без приоритета, и релизы перестают выходить не из-за разработки, а потому что некому сказать «выпускаем».
Объём мы измеряем часами команды в месяц: в программах сопровождения это 36, 60, 120 или 220 часов. Это не цена, а мера нагрузки. Тридцать шесть часов — присмотр и мелкие правки: обновления зависимостей, реакция на изменения правил, пара релизов в квартал. Сто двадцать и больше — поток изменений уровня выделенной группы, когда приложение развивается параллельно основному продукту. Какая величина нужна вам, видно из того, сколько релизов в год вы собираетесь выпускать и сколько сценариев завязано на внешние сервисы. Разложите свой месяц по пяти строкам ниже: первые три приходят по внешнему расписанию, две последние — по вашему.
За два года у приложения, скорее всего, появится второй канал распространения — хотя бы потому, что бизнес уже видел, как приложение исчезает из магазина не по своей вине. Это отдельная работа, и считать её нужно отдельно.
Переписывать приложение с нуля для этого, как правило, не требуется: код переносится с ограниченными доработками. Основной объём — ревизия зависимостей и замена внешних сервисов, которые в такой сборке недоступны: уведомления, карты, аналитика, оплата. То есть опять не функции, а то, на чём они держатся.
Жить одновременно в нескольких магазинах можно, и чаще всего так и делают: каналы не конфликтуют. Плата — вторая сборка, которую нужно собирать, проверять и выпускать при каждом релизе, а не один раз при подключении.
Честный раздел, без которого статья была бы рекламой. Кроссплатформенное решение закрывает большинство задач: кабинет, магазин, сервис, обучение, внутренний инструмент. Но есть условия, при которых на дистанции оно начинает мешать, и назвать их стоит заранее.
Первое — приложение глубоко работает с устройством: тяжёлая графика, постоянная работа с камерой, фоновые процессы с особыми требованиями, свежие возможности платформы, которые нужны сразу после их выхода. В этом случае вы регулярно ждёте, пока нужное появится в общем слое, и пишете обходные решения — а обходные решения и есть то, что потом ломается при каждом обновлении.
Второе — у вас уже есть сильные команды под обе платформы по отдельности, и общий код для них не упрощение, а лишний посредник. Третье — продукт сознательно расходится на двух платформах: разные сценарии, разные экраны, разная аудитория. Тогда единая кодовая база экономит всё меньше, а стоит внимания столько же.
И обратная сторона, о которой тоже надо сказать: два нативных приложения — это два цикла выпуска, два набора зависимостей и два календаря требований магазинов. Через два года нативная пара даёт вдвое больше циклов выпуска и вдвое больше наборов зависимостей — своих замеров трудозатрат на этот счёт у нас нет, но арифметика релизов видна без замеров. Ни один из подходов не отменяет поддержку — они отменяют разные её части.
Если вы сейчас выбираете подход или прикидываете нагрузку второго года — пришлите нам не техническое задание, а четыре вещи: сколько релизов в год вы планируете, какие внешние сервисы приложение использует, какая у вас статистика по версиям систем у аудитории и есть ли своя команда, которая со временем заберёт продукт. Этого достаточно, чтобы назвать разумный объём часов в месяц и сказать, при каких условиях вам лучше подойдёт нативная пара, а при каких — одна кроссплатформенная сборка. Если из ответов выйдет, что поддержка вам нужна в минимальном объёме, мы так и скажем.
Посмотрим ваш сайт, скажем, что мешает ему приводить клиентов, и какие каналы дадут результат в вашей практике. Без обязательств, отвечаем в течение рабочего дня.