Гибридное или нативное приложение: чем платишь за экономию
Разработка кроссплатформенных приложений на Capacitor: сколько экономит гибрид, где он неотличим от натива, где проигрывает и что ломается в реальности.
Разработка кроссплатформенных приложений экономит около 40% бюджета и оставляет один релизный цикл вместо двух. Платите вы за это производительностью в сложных анимациях и зависимостью от прослойки между вебом и системой. На платформе событий и билетов гибридный подход дал экономию 10 000 $+ против нативной разработки, и приложение при этом делает всё, что должно: билеты, оплату, сканирование QR, бонусы, фотоальбомы.
Дальше - как это устроено внутри, где разницу с нативом видно, где не видно вообще, и что в гибриде реально ломается. Я владел таким приложением два с половиной года на обеих платформах, так что список поломок не теоретический.
Кроссплатформенная разработкаот 350 000 до 1 200 000 ₽сроки: 8-16 недель
Как устроен Capacitor
Приложение на Capacitor - это нативный проект (Xcode для iOS, Gradle для Android), внутри которого лежит WebView на весь экран, а в нём работает обычное веб-приложение: Vue, React, что угодно. Плюс мост между JavaScript и нативным кодом.
Три слоя, и границы между ними жёсткие:
- Веб-слой. Вся ваша логика и интерфейс. Один код на iOS, Android и браузер.
- Мост. Асинхронный канал: из JS уходит вызов с сериализуемыми аргументами, из натива приходит ответ или событие. На iOS это WKScriptMessageHandler, на Android - JavascriptInterface. Всё, что ездит через мост, проходит через JSON, и это первое место, где можно упереться в производительность, если гонять туда мегабайты.
- Нативные плагины. Классы на Swift и Kotlin, которые регистрируются в мосте и получают типизированный интерфейс на TypeScript. Камера, файлы, биометрия, пуши, геолокация, любой системный API.
Ключевое отличие от «сайта в обёртке»: WebView не грузит ваш домен по сети. Ассеты лежат внутри бандла и отдаются локальной схемой (capacitor:// на iOS, https://localhost на Android). Приложение открывается без интернета, работает с локальной базой и обращается к серверу только за данными. Это же отличие решает вопрос с ревью App Store, о котором ниже.
Чем это отличается от React Native и Flutter
Все три подхода называют кроссплатформенными, но устроены они по-разному.
| Что рисует интерфейс | Язык | Веб из той же базы | |
|---|---|---|---|
| Capacitor | системный WebView | TypeScript, любой веб-фреймворк | да, буквально тот же билд |
| React Native | нативные компоненты через свой мост | TypeScript, React | частично, через react-native-web |
| Flutter | собственный движок рендеринга Skia/Impeller | Dart | да, но бандл тяжёлый и SEO нет |
React Native отдаёт разметку в настоящие нативные вьюхи, поэтому списки и жесты у него ближе к нативу, но экосистема веб-библиотек недоступна: CSS там свой, DOM нет. Flutter рисует всё сам на канве, поэтому картинка идентична на обеих платформах, но и системные элементы он тоже рисует сам, со всеми последствиями при смене версии ОС.
Capacitor честно оставляет вам веб. Это значит доступ ко всей веб-экосистеме, знакомый CSS, обычные devtools и возможность запустить тот же код в браузере. И это же значит, что вы получаете все особенности WebView, включая чужие баги.
Где гибрид неотличим от натива
Списки, формы, каталоги, карточки товаров, личные кабинеты, чаты, оплата, онбординг, настройки. Всё, что состоит из прокрутки, нажатий и переходов между экранами. На устройствах последних пяти лет WebView отрисовывает такой интерфейс за тот же кадр, что и нативный код, и пользователь разницы не увидит.
За два с половиной года владения архитектурой гибридного приложения на iOS и Android я ни разу не получил жалобу вида «приложение тормозит» на обычных экранах. Жалобы были на конкретные вещи: обработка длинного видео, галерея на несколько тысяч фотографий. То есть ровно там, где гибрид действительно упирается.
Практическая проверка простая: если ваш экран можно описать как «список, форма или карточка» - гибрид его закроет полностью.
Где разница видна
Сложные жесты. Интерактивное перетаскивание с физикой, свайп с параллаксом, жест, который надо прервать на середине и вернуть обратно. В вебе такое делается, но каждый кадр жеста проходит через JS, и на слабом железе это заметно.
Анимации на 60 fps на бюджетных Android. На флагманах всё ровно. На устройстве за 12 тысяч рублей с урезанным WebView сложная анимация может пойти рывками, особенно если параллельно идёт сетевой запрос. Лечится дисциплиной: только transform и opacity, никаких анимаций height и box-shadow, will-change там, где надо, и никогда - везде.
Большие списки медиа. Тысячи изображений с превью в вебе требуют виртуализации, ленивой загрузки и аккуратной работы с памятью. WebView умеет отдать вкладку под нож при нехватке памяти, и приложение внезапно перезагружает страницу. Нативный список этой проблемы не имеет.
Первый запуск. Холодный старт гибридного приложения обычно на пару сотен миллисекунд дольше: WebView надо поднять. Заметно на старых устройствах, лечится сплэш-экраном и разумным размером бандла.
Разрез приложения: приложение в сторах
Как устроено гибридное приложение
Один веб-слой, мост и нативные плагины поверх двух платформ. Ниже моста код пишется отдельно под iOS и Android.
iOS
App Store, ревью 1-3 дня
Android
Google Play, ревью до суток
Оболочка Capacitor
- WebView
- мост JS ↔ Native
- сборка .ipa и .aab
Нативные плагины
- камера и галерея
- push-уведомления
- геолокация
- биометрия
- файлы и шаринг
Один код Vue 3 + TypeScript
- экраны и навигация
- бизнес-логика
- состояние
- запросы к API
Нативного кода в проекте только оболочка и плагины. Экраны, логика и данные - общие, поэтому правка уезжает сразу на обе платформы.
Разработка кроссплатформенных приложений: что реально ломается
Список из практики, а не из документации.
Мажорное обновление Capacitor. Переход с 4 на 5 у меня занял не день, а неделю. Ломается не ядро - ломаются плагины: каждый сторонний плагин должен выпустить свою совместимую версию, а часть авторов этого не делает никогда. Вместе с Capacitor обычно едет и минимальная версия iOS, и целевой Android SDK, а значит пересборка, проверка разрешений и новый прогон по устройствам. Планировать такое обновление надо раз в год как отдельную задачу, а не «между делом».
WebView на Android разный. Он обновляется через Google Play отдельно от системы, и на устройствах некоторых вендоров бывает старым или подпиленным. Проблемы всплывают на конкретных моделях: где-то не работает backdrop-filter, где-то иначе считается высота при открытой клавиатуре, где-то тормозит position: sticky. Единственное лекарство - тестировать на реальных дешёвых устройствах, а не только в эмуляторе.
WKWebView на iOS и скролл. Резиновый скролл всего документа, который утаскивает интерфейс вместе с шапкой. Прокрутка, которая продолжается после того, как открылось модальное окно. Клавиатура, которая поднимает весь вебвью вместо того, чтобы поджать контент. Лечится связкой из фиксированной высоты контейнера, overscroll-behavior, отключения зума и нативного плагина клавиатуры, который сообщает её высоту в веб-слой.
Safe area. Чёлки, островки, скруглённые углы, нижняя полоса жестов. Всё это учитывается через env(safe-area-inset-*), и если забыть про нижний отступ, кнопка «Оплатить» окажется под полосой жестов. На Android аналогичная история с вырезами и жестовой навигацией. Это не сложно, но это надо помнить на каждом экране.
Память. WebView живёт в общем бюджете памяти приложения. Утечка в веб-слое приводит не к тормозам, а к тому, что система убивает процесс. Sentry ловит это как «приложение перезапустилось», и найти причину без профайлера тяжело.
Чем гибрид выигрывает
Обновления мимо ревью. Веб-слой можно обновлять по воздуху: собранные ассеты выкладываются на сервер, приложение скачивает новую версию и применяет при следующем запуске. Критичный баг чинится за час, а не за неделю ожидания ревью. Ограничение: так обновляется только веб-часть. Всё, что нативное, - плагины, разрешения, иконки, версии SDK - едет через стор. На прошлом мобильном проекте у меня был настроен CodePush с откатом на предыдущую версию, и это спасало не раз.
Один набор всего. Одна дизайн-система вместо двух, один набор тестов, один линтер, один процесс код-ревью. Правка едет в оба приложения одновременно, а не «сначала iOS, Android через спринт».
Веб как побочный продукт. Тот же код открывается в браузере. Для платформы событий это оказалось важнее, чем казалось: админка и часть пользовательских сценариев жили в вебе, а мобильное приложение переиспользовало компоненты.
Веб-экосистема. Библиотеки под графики, редакторы, карты, аудио - всё это существует в вебе в готовом виде. Свою аудиоволну я собрал на wavesurfer за день, нативный аналог занял бы неделю на каждой платформе.
Обновляемость самой платформы. За время работы над тем же приложением я перевёл проект с Vue 2 на Vue 3 и с Vue CLI на Vite, не останавливая поставку релизов. Такое делается инкрементально именно потому, что под капотом обычный веб: миграция шла по частям, а сборка продолжала выкатываться. В нативном проекте аналогичная смена архитектуры обычно означает заморозку фич.
Честная граница
Гибрид не подходит для игр, тяжёлой графики (3D, AR, фильтры реального времени над потоком с камеры) и постоянной фоновой работы с железом: непрерывный GPS-трекинг, обмен по Bluetooth в фоне, обработка видеопотока на лету. Там нужен натив, и спорить не о чем.
Отдельный случай - когда приложение и есть продукт, а его отзывчивость и есть конкурентное преимущество. Если вы делаете редактор фото, музыкальный инструмент или соцсеть на десятки миллионов пользователей, разница в 16 миллисекунд на кадр начинает стоить денег.
Всё остальное - каталоги, заказы, кабинеты, билеты, лояльность, внутренние инструменты, медиа с разумной обработкой - гибрид закрывает полностью, за 40% меньших денег и с одной кодовой базой на поддержке. Как я это делаю, из чего складывается срок и что входит в проект, описано на странице кроссплатформенной разработки.
Ещё про приложения
3 статьи-
Capacitor, React Native или Flutter: чем платит бизнес за выбор
Flutter или React Native, а может Capacitor: экономия против натива у всех похожая. Разбираю, чем именно платит владелец приложения при каждом выборе.
38 показов в месяц у вопроса -
Что такое PWA и когда оно заменяет приложение
Что такое PWA простыми словами: сайт с иконкой на экране, офлайном и уведомлениями. Что умеет, чего не умеет на iOS и в каких случаях заменяет приложение за 350 000 ₽.
860 показов в месяц у вопроса -
Как выложить приложение в App Store и Google Play
Как выложить приложение в App Store и Google Play: аккаунты, подпись, карточка, сроки ревью и реальные причины отказов Apple с номерами гайдлайнов.
300 показов в месяц у вопроса




