Реалізація 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 дні. Зв'яжіться з нами, щоб обговорити ваші вимоги.







