Capacitor: от веба к мобильным приложениям. Часть 1. Миграция проекта на Capacitor
- среда, 28 января 2026 г. в 00:00:09
В первой части цикла мы разобрались, зачем вообще нужен Capacitor и почему он стал адекватным выбором для кроссплатформенной разработки.
Теперь переходим к самому болезненному и интересному этапу: миграции уже существующего веб-приложения.
Главное преимущество: код не переписывается.
React остается React;
бизнес-логика, API-клиенты, сторы, формы и UI остаются прежними.
Если приложение уже адаптивное, большая часть работы выполнена заранее.
Команда продолжает работать в привычном SPA или SSR-стеке.
Нет необходимости срочно изучать Swift, Kotlin или особенности нативных UI-фреймворков.
Capacitor создает полноценные iOS и Android проекты;
не скрывает Xcode и Android Studio;
позволяет писать нативный код напрямую при необходимости.
Это принципиальное отличие от Cordova, где нативная часть чаще всего выглядела как «черный ящик».
Capacitor обновляется синхронно с:
iOS SDK;
Android SDK;
требованиями App Store и Google Play.
Это снижает риск внезапно оказаться с приложением, которое больше нельзя собрать или опубликовать.
Для таких проектов Capacitor чаще всего является логичным следующим шагом, но не без нюансов.
нет динамической загрузки плагинов;
нативные проекты полностью доступны для правок;
плагины используют современные API;
обновления iOS и Android переживаются заметно проще.
Cordova-плагины не совместимы напрямую с Capacitor;
часть функциональности придется заменить официальными плагинами Capacitor;
кастомные плагины потребуется переписать.
Зато итоговая архитектура получается более стабильной и предсказуемой.
Имеем:
старое React-приложение на Webpack;
Node.js версии 16;
проект без SSR;
сборка отдает статические файлы.
Важно: версия Capacitor должна быть совместима с Node.js проекта.
Для Node.js 16:
рекомендуется использовать Capacitor 5 или 6;
Capacitor 7 ориентирован на более свежие версии Node.js.
Актуальная таблица совместимости:
Версия Capacitor | Минимальная Node.js | Рекомендуемая Node.js | Комментарий |
|---|---|---|---|
Capacitor 7 | 18.x | 18.x / 20.x | Актуальная версия для новых проектов |
Capacitor 6 | 16.x | 18.x | Компромисс для legacy-проектов |
Capacitor 5 | 14.x | 16.x | Часто встречается в старых проектах |
Capacitor 4 | 14.x | 16.x | Постепенно устаревает |
Capacitor 3 | 12.x | 14.x | Legacy |
Capacitor 2 | 10.x | 12.x | Фактически мертв |
Для Node.js 16 выбираем Capacitor 6 и Capacitor cli 5:
npm install @capacitor/core@6 @capacitor/android@6 @capacitor/ios@6
npm install -D @capacitor/cli@5
npx cap init
В процессе инициализации:
указываем название приложения:

указываем appId приложения:

В конечном итоге создастся файл capacitor.config.ts со следующим содержанием:
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'ru.smartlamp',
appName: 'smart_lamp-front',
webDir: 'build',
server: {
androidScheme: 'https'
}
};
export default config;
Убедитесь, что:
npm run build создает статические файлы;
приложение корректно открывается без сервера.
Если директория сборки у вас отличается от build то поменяйте ее.
Затем нужно создать директории самих нативных проектов:
npx cap add android
npx cap add ios
После выполнения этих команд у нас появляются 2 директории:

Capacitor загружает статические файлы в WebView.
Классический SSR:
требует Node.js сервера;
рендерит HTML на лету.
Если SEO внутри мобильного приложения не критичен:
next build
next export
На выходе получаем статический билд, полностью совместимый с Capacitor.
веб-версия остается с SSR;
мобильная версия работает как SPA или SSG.
Перед тем как рассказать про минимальную настройку Android studio и Xcode считаю необходимым показать сводные таблицы совместимости OC и IDE с версией Capacitor:

И Версий iOS и Android:

Это нам понадобится при выполнении дальнейших шагов. Далее я коротко опишу минимальную настройку под разные системы.
Для разработки и сборки iOS приложения Вам в любом случае понадобится устройство на macOS (нет, через эмулятор или виртуалку не получится).
Capacitor требует:
Android Studio;
Android SDK;
Android Emulator.
Скачать Android Studio с официального сайта.
Установить Android SDK через SDK Manager.
Создать виртуальное устройство (AVD).
После скачивания и установки Android Studio Вам нужно открыть директорию android вашего приложения

Дальше как правило происходят вещи от которых никуда не деться, а именно всевозможные ошибки совместимости версий Java, Gradle (сборщик) и т.д.
Это не означает что вы обязательно сталкнетесь с проблемами, но в нашем случае основная проблема:
Несовместимая версия Gradle
В таком случае Android studio сам предлагает повысит версию до совместимой. Из предложенных на скриншоте вариантов Я бы посоветовал выбрать самую последнюю версию, а именно 8.10. Сам выбрал что-то посредине, а именно 8.7.
После того как Вы, если это конечно будет необходимо, установите нужную версию Gradle должна произойти синхронизация проекта.

После успешной синхронизации IDE выведет что-то подобное:

Если в процессе у Вас что-то пошло не так, спросите у chatGPT или Google. Как правило ошибки распространенные. Возможно что-то связанное с ОС или с версией Java (если она у Вас есть, если нет поставьте).
Далее есть два варианта:
Установить эмулятор устройства
Подключить по USB к ПК физическое устройство
В первом случае вам нужно зайти в меню устройств в IDE, нажать добавить устройство и выбрать любое понравившееся вам устройство. В нашем случае я выбрал Pixel 9. И установить эмулятор:

Во втором случае подключайте Android устройство по USB, но перед этим устройство нужно подготовить к отладке.
Перед запуском мобильного приложение нужно запустить dev сервер. В моем случае это делается через react-scripts в Вашем может быть что угодно, но главное тут соблюсти несколько вещей:
Общий порт
Общий ip адресс
На Windows узнать свой IP можно выполнив команду:
ipconfig
На MacOS/Linux выполнив:
ifconfig | grep inet
После чего запускаете свой dev сервер на этом IP и на любом порте.
Теперь можно запускать мобильной приложение выполнив:
npx cap run android --host 'ваш ip' --port 'такой же как запущенного dev сервера'
И вы должны увидеть работающее приложение в эмуляторе:

macOS;
установленный Xcode совместимой версии;
Xcode Command Line Tools;
Возможно понадобится установка CocoaPods;
После того как мы выполнили npx cap add ios в прошлых шагах, мы можем открыть открыть наш проект в xcode, но перед этим мы дожны убедиться в совместимости версий.
Далее выполняем команду:
npx cap open ios
Откроется проект в Xcode. Если все хорошо то далее можем выполнить команду:
npx cap run ios --host 'ваш ip' --port 'такой же как запущенного dev сервера'
Dev сервер при этом должен быть запущен. После запуска этой команды мы получаем долгожданный результат:

Для сборки apk файла нашего приложения нам понадобится файл подписи приложения.
Создать его можно 2 способами:
keytool (нужна установленная Java);
keytool -genkeypair -v \
-keystore habr-capacitor.jks \
-keyalg RSA \
-keysize 2048 \
-validity 10000 \
-alias habr-capacitor
Нужно будет указать:
Пароль keystore;
Имя, организация и т.д. — можно писать что угодно;
Пароль ключа — можно такой же, можно другой;
На выходе нужный нам файл habr-capacitor.jks.
Обычно кладут в android/app/.
Обновляем android/app/build.gradle:
apply plugin: 'com.android.application'
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
namespace "ru.bast.smartlamp"
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {
applicationId "ru.bast.smartlamp"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}
repositories {
flatDir{
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
implementation project(':capacitor-android')
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
implementation project(':capacitor-cordova-android-plugins')
}
apply from: 'capacitor.build.gradle'
try {
def servicesJSON = file('google-services.json')
if (servicesJSON.text) {
apply plugin: 'com.google.gms.google-services'
}
} catch(Exception e) {
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
}
Также обновляем keystore.properties в корне директории android. Я указал:
storePassword=habrcapacitor
keyPassword=habrcapacitor
keyAlias=habrcapacitor
storeFile=habr-capacitor.jks
Разумеется keystore.properties нужно добавить в .gitignore.
Один keystore = одно приложение.
Потерял keystore ключ → потерял обновления в Google Play.
Именно поэтому имеет смысл генерировать подписи через Android Studio и хранить их на серверах Google.
После всех манипуляций мы наконец-то можем выполнить команду сборки:
cd android && ./gradlew assembleRelease
После чего наш apk файл будет лежать по пути android/app/build/outputs/apk/release.
Сборка под iOS заключается в том чтобы создать архив и отправить его на сервера Apple для дальнейшего распространения среди различных групп пользователей, будь то тестировщики или релизный билд. Чтобы выполнить сборку и следующие шаги Вам необходимы:
Аккаунт Apple который будет выступать в качестве разработчика;
Оплаченная подписка на год в размере $100;
Signin сертификат который так же требует подписки;
Можно конечно сделать это и бесплатно для запуска приложения на своем смартфоне, но это как по мне сомнительная возможность.
Именно поэтому в этой статье не считаю нужным касаться дальнейшей сборки под iOS, так как рассказ выйдет довольно долгим. Более подробно про сборку готового приложения Я распишу в другой статье.
Кстати для того чтобы выложить Android приложение в Google Play тоже нужно покупать подписку, но это не запрещает создать apk файл и выложить его скажем в RuStore бесплатно или распространять его как Вам угодно.
Миграция приложения с cordova принципиально отличается от вышеприведенной инструкции лишь тем, что cordova использует специфические и зачастую старые версии Android/iOS плагинов. В общих чертах миграция такого проекта будет заключаться в следующем:
Установка Capacitor и т.д по инструкции
Аудит используемых плагинов и установка аналогов как официальных так и плагинов сообщества
Удаление Cordova и установка памятника
Поэтому в этой статье касаться миграции такого проекта я не буду, потому что она касается в основном работы с плагинами.
Миграция существующего веб приложения на Capacitor — это:
быстрый способ выйти в мобильные сторы;
минимальные изменения в кодовой базе;
разумный компромисс между вебом и нативом.
Capacitor не идеален и не заменяет нативную разработку, но для большинства бизнес-приложений он закрывает задачу быстрее и дешевле, чем альтернативы.
В следующей статье мы разберем:
Установка официальных плагинов Capacitor
Установка community плагинов
Миграция с Cordova плагинов на Capacitor
Разработка собственного плагина
На этом у меня все. Пишите любые интересующие вас вопросы в комментарии и в личку.
Ссылки: