В первой части цикла мы разобрались, зачем вообще нужен Capacitor и почему он стал адекватным выбором для кроссплатформенной разработки.
Теперь переходим к самому болезненному и интересному этапу: миграции уже существующего веб-приложения.
Оглавление
Преимущества перехода на 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.
Это снижает риск внезапно оказаться с приложением, которое больше нельзя собрать или опубликовать.
Недостатки и ограничения
Если проект раньше использовал Cordova
Для таких проектов Capacitor чаще всего является логичным следующим шагом, но не без нюансов.
Что становится лучше по сравнению с Cordova
нет динамической загрузки плагинов;
нативные проекты полностью доступны для правок;
плагины используют современные API;
обновления iOS и Android переживаются заметно проще.
На что стоит обратить внимание при миграции
Cordova-плагины не совместимы напрямую с Capacitor;
часть функциональности придется заменить официальными плагинами Capacitor;
кастомные плагины потребуется переписать.
Зато итоговая архитектура получается более стабильной и предсказуемой.
Пример миграции старого React + Webpack проекта
Имеем:
старое React-приложение на Webpack;
Node.js версии 16;
проект без SSR;
сборка отдает статические файлы.
Выбор версии Capacitor
Важно: версия 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 | Фактически мертв |
Установка Capacitor
Для 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 директории:

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

И Версий iOS и Android:

Это нам понадобится при выполнении дальнейших шагов. Далее я коротко опишу минимальную настройку под разные системы.
Для разработки и сборки iOS приложения Вам в любом случае понадобится устройство на macOS (нет, через эмулятор или виртуалку не получится).
Настройка Android Studio
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 сервера'
И вы должны увидеть работающее приложение в эмуляторе:

Настройка Xcode
Требования
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 сервер при этом должен быть запущен. После запуска этой команды мы получаем долгожданный результат:

Минимальная сборка под Android
Для сборки 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
Сборка под iOS заключается в том чтобы создать архив и отправить его на сервера Apple для дальнейшего распространения среди различных групп пользователей, будь то тестировщики или релизный билд. Чтобы выполнить сборку и следующие шаги Вам необходимы:
Аккаунт Apple который будет выступать в качестве разработчика;
Оплаченная подписка на год в размере $100;
Signin сертификат который так же требует подписки;
Можно конечно сделать это и бесплатно для запуска приложения на своем смартфоне, но это как по мне сомнительная возможность.
Именно поэтому в этой статье не считаю нужным касаться дальнейшей сборки под iOS, так как рассказ выйдет довольно долгим. Более подробно про сборку готового приложения Я распишу в другой статье.
Кстати для того чтобы выложить Android приложение в Google Play тоже нужно покупать подписку, но это не запрещает создать apk файл и выложить его скажем в RuStore бесплатно или распространять его как Вам угодно.
Миграция Cordova приложения
Миграция приложения с cordova принципиально отличается от вышеприведенной инструкции лишь тем, что cordova использует специфические и зачастую старые версии Android/iOS плагинов. В общих чертах миграция такого проекта будет заключаться в следующем:
Установка Capacitor и т.д по инструкции
Аудит используемых плагинов и установка аналогов как официальных так и плагинов сообщества
Удаление Cordova и установка памятника
Поэтому в этой статье касаться миграции такого проекта я не буду, потому что она касается в основном работы с плагинами.
Итоги
Миграция существующего веб приложения на Capacitor — это:
быстрый способ выйти в мобильные сторы;
минимальные изменения в кодовой базе;
разумный компромисс между вебом и нативом.
Capacitor не идеален и не заменяет нативную разработку, но для большинства бизнес-приложений он закрывает задачу быстрее и дешевле, чем альтернативы.
В следующей статье мы разберем:
Установка официальных плагинов Capacitor
Установка community плагинов
Миграция с Cordova плагинов на Capacitor
Разработка собственного плагина
На этом у меня все. Пишите любые интересующие вас вопросы в комментарии и в личку.
Ссылки:
