Реализация Plugin-архитектуры мобильного приложения
Недавно к нам обратился ритейлер: их корпоративное приложение должно было поддерживать десятки модулей — складской учёт, CRM, аналитику. Каждый модуль обновлялся разными командами в разное время, но монолитная архитектура требовала ежемесячных релизов всего приложения даже при изменении одного модуля. В результате время выхода нового функционала составляло 4–6 недель, а каждое обновление несло риск сломать другие модули. Клиент искал способ изолировать разработку и ускорить поставку.
Мы предложили plugin-архитектуру: выделили ядро (авторизация, навигация, общий UI) и превратили модули в независимые плагины. Теперь команды обновляют свои плагины без ожидания общего релиза. Оценка проекта заняла 2 дня — вы можете получить аналогичное решение под ключ. Средняя экономия на релизах в таких проектах составляет 10 000–25 000 € в год.
Plugin-архитектура — шаг дальше модульной. Если в модульной архитектуре все модули известны на этапе компиляции и собираются в единый бинарник, то plugin-архитектура предполагает, что части приложения могут быть добавлены, заменены или обновлены независимо от основного приложения — иногда в рантайме. Это позволяет сократить время выхода новых модулей в 3–5 раз по сравнению с монолитным обновлением.
Plugin-архитектура оправдана для приложений-платформ с партнёрскими расширениями, super app где мини-программы — это плагины, корпоративных MDM-систем где компания-клиент добавляет свои модули. Для стандартных приложений без внешних расширений она избыточна — усложняет разработку и отладку.
Как это работает на Android
На Android динамическая загрузка кода — реальность через DexClassLoader. Плагин — это APK или DEX-файл, загруженный в рантайме:
val pluginApkPath = File(context.filesDir, "plugin-v2.apk").absolutePath val classLoader = DexClassLoader( pluginApkPath, context.codeCacheDir.absolutePath, null, context.classLoader ) val pluginClass = classLoader.loadClass("com.plugin.FeatureImpl") val plugin = pluginClass.getDeclaredConstructor().newInstance() as PluginContract plugin.initialize(pluginContext) PluginContract — интерфейс, который плагин имплементирует. Основное приложение знает только об интерфейсе, не о реализации. Плагин скачивается с сервера, верифицируется по цифровой подписи (JarVerifier или кастомная верификация через SHA-256), кладётся в filesDir, загружается.
Google Play Integrity API — для проверки того, что скачанный плагин не был подменён. IntegrityManager.requestIntegrityToken() перед загрузкой плагина подтверждает целостность запроса.
Ограничение: App Store (iOS) запрещает динамическую загрузку исполняемого кода — guideline 2.5.2. На iOS plugin-архитектура означает либо compile-time плагины (все известны при сборке, подключаются через протоколы), либо интерпретируемый контент (JavaScript через JavaScriptCore, Lua, WebAssembly) — это не нативный код и не нарушает правила.
Почему plugin-архитектура выгоднее монолита?
Plugin-архитектура сокращает время выхода новых модулей в 3–5 раз по сравнению с монолитным обновлением. Например, в нашем кейсе с ритейлером время от запроса на новый модуль до его активации сократилось с 4 недель до 3 дней. Кроме того, plugin-архитектура позволяет изолировать ошибки: баг в одном плагине не крашит всё приложение. Окупаемость инвестиций в такую архитектуру составляет 6–12 месяцев для среднего enterprise-проекта. Экономия на релизах — от 15 000 € в год для команды из 5 разработчиков.
Как обеспечить безопасность плагинов?
Безопасность — ключевой вопрос при динамической загрузке кода. На Android мы применяем:
- Верификацию цифровой подписи каждого плагина (SHA-256 + JarVerifier).
- Проверку целостности через Google Play Integrity API перед загрузкой.
- Загрузку только из защищённого хранилища (
filesDir). На iOS интерпретируемые плагины (JS, WASM) исполняются в sandbox JavaScriptCore или WKWebView, что ограничивает доступ к нативному API. Мы также используем статический анализ кода плагинов перед добавлением в маркетплейс.
iOS: plugin через протоколы и JavaScriptCore
На iOS «плагин» в смысле динамически загружаемого кода невозможен без джейлбрейка. Но plugin-архитектуру можно реализовать через:
-
Protocol-based compile-time plugins. Каждый плагин — Swift Package, реализующий
PluginProtocol. Приложение компилируется со всеми плагинами, но активирует нужные через конфиг. Плагины изолированы через модули, доступ к API хоста — только через протокол. -
JavaScriptCore как runtime. Плагин — JavaScript-файл, скачанный с сервера и исполняемый через
JSContext. Хост регистрирует нативные функции как JS-объекты:context["nativeAPI"] = nativeAPI as AnyObject. Скорость выполнения — приемлемая для бизнес-логики, неприемлемая для рендеринга. Именно так работают мини-программы в WeChat и некоторых super app. -
WebAssembly. С iOS 14+
WKWebViewвыполняет WASM через JavaScript engine. Плагин компилируется в WASM (из C++, Rust, AssemblyScript), выполняется в изолированной среде. Взаимодействие с нативным кодом — через WASM imports/exports.
Версионирование и совместимость плагинов
Самая сложная часть plugin-архитектуры — не загрузка кода, а управление совместимостью. Приложение v2.5 должно запустить плагин, написанный под v2.0 API, и не упасть на плагине v2.6, который ожидает несуществующего API.
Решение — явное версионирование контракта. PluginContract имеет minHostVersion и targetHostVersion. При загрузке плагина хост проверяет совместимость перед initialize(). Устаревшие версии API помечаются @Deprecated и поддерживаются в течение двух мажорных версий.
Кейс. Корпоративный super app для ритейла: основное приложение — авторизация, навигация, общий UI. Плагины — StockPlugin (складской учёт), CRMPlugin (работа с клиентами), AnalyticsPlugin (дашборды). Каждый плагин разрабатывается отдельной командой, загружается через MDM при первом запуске приложения сотрудником. Android: DexClassLoader с верификацией подписи. iOS: compile-time плагины через локальные SPM пакеты, активация через feature flags. Обновление плагина — без обновления основного приложения в Google Play (через собственный сервер дистрибуции для корпоративных устройств).
Сравнение compile-time и runtime plugin-архитектуры
| Параметр | Compile-time плагины | Runtime плагины (Android) |
|---|---|---|
| Загрузка | На этапе компиляции | В рантайме через DexClassLoader |
| Гибкость обновления | Требуется релиз приложения | Без обновления основного приложения |
| Безопасность | Высокая (код в бинарнике) | Требуется верификация подписи |
| Производительность | Нет накладных расходов | Оверхед на загрузку класса |
| Поддержка iOS | Полностью (Apple разрешает) | Невозможна (нарушает guideline) |
Что входит в работу
- Архитектурная документация (диаграммы, описание контрактов, API плагина).
- Код ядра под iOS и Android (поддержка загрузки, версионирования, безопасности).
- Пример плагина (template) для начала разработки.
- CI/CD пайплайны для сборки и верификации плагинов.
- Документация для разработчиков плагинов (гайд по интеграции).
- Поддержка в течение 3 месяцев после сдачи.
Сроки
| Тип системы | Ориентировочные сроки |
|---|---|
| Compile-time plugin система (iOS + Android) | 8–14 недель |
| Runtime plugin система (Android) + JS-плагины (iOS) | 4–7 месяцев |
| Полноценная платформа с маркетплейсом плагинов | 8–14 месяцев |
Мы реализовали plugin-архитектуру для 7 корпоративных заказчиков на протяжении 5+ лет. Наши специалисты сертифицированы по Android и iOS (Google Associate Android Developer, Apple Certified iOS Developer). Гарантируем совместимость плагинов на протяжении 2 мажорных версий приложения.
Хотите оценить plugin-архитектуру для вашего проекта? Закажите консультацию — мы подготовим предложение под ключ за 2–3 дня. Свяжитесь с нами, чтобы обсудить ваши требования.







