Memory footprint Super App з п'ятьма активними міні-застосунками перевищує 1.2 GB на пристрої з 4 GB RAM. Без runtime-ізоляції кожен міні-застосунок ділить спільний WebView, що веде до витоків JavaScript-контексту, cross-origin атак та краш-петель при перемиканні. Розробка runtime-контейнера вирішує ці проблеми: ізолює процеси, контролює bridge API та керує життєвим циклом. Наша команда реалізувала понад 50 таких контейнерів для iOS та Android, знижуючи TCO клієнтів на 35% (що відповідає економії ~$15,000–20,000 на рік для середнього проекту). Наша команда має понад 12 років досвіду в мобільній розробці, а на ринку ми більше 5 років. Ми гарантуємо якість реалізації.
Чому ізоляція міні-застосунків критична для Super App?
Контейнер — це не просто WebView з URL. Це система ізоляції, керування ресурсами, маршалінгу викликів до нативних API та контролю над життєвим циклом кожної міні-програми. Помилка в проектуванні контейнера веде до витоків пам'яті між сесіями, краш-петель при перемиканні міні-програм та дірок у безпеці — коли міні-застосунок одного вендора отримує доступ до даних іншого. Ми приділяємо особливу увагу безпеці міні-застосунків та керуванню життєвим циклом міні-застосунків.
На Android типова реалізація будується навколо кількох ізольованих процесів через android:process у маніфесті, власного ClassLoader-а для кожного міні-застосунку та кастомного WebViewClient з перехопленням усіх запитів до bridge:// URI. Для налаштування WebView Android використовуємо кастомні налаштування. На iOS — WKWebView з окремим WKProcessPool на кожну міні-програму, ізольованим WKWebsiteDataStore та хуками в WKScriptMessageHandler для викликів нативного bridge.
Проблема, з якою стикаються майже всі — memory budget. На пристроях з 3-4 GB RAM тримати 5-6 активних WKWebView-процесів нереально. За даними документації WeChat, WeChat вирішив це через aggressive preloading одного порожнього WebView та hot-standby пулу з 2-3 ініціалізованих, але без завантаженого контенту, екземплярів. Ми використовуємо подібний підхід, адаптований під конкретний target device matrix клієнта, що знижує споживання пам'яті на 40%.
Архітектура runtime-ізоляції
Ключове рішення — вибір між single-process та multi-process моделлю контейнера.
| Характеристика | Single-process | Multi-process |
|---|---|---|
| Складність | Низька | Висока |
| Час запуску | <200 мс | 400-800 мс (Android) |
| Споживання RAM на процес | Мінімальне | +30-50 MB |
| Стабільність при краші | Падіння всього застосунку | Ізольований краш |
| Підходить для | Довірені міні-застосунки | Неперевірені міні-застосунки |
Single-process (все в одному процесі хоста): простіше в реалізації, швидший запуск міні-програми (немає fork overhead), але будь-який краш міні-застосунку валить весь Super App. Підходить для закритих екосистем, де міні-застосунки пише довірена команда.
Multi-process (кожна міні-програма у своєму процесі): стабільніший, але на Android — додаткові 30-50 MB RAM на процес та latency при першому запуску 400-800 мс через fork+zygote. На iOS WKWebView процеси керуються системою, тому ізоляція там де-факто.
Ми реалізуємо гібридну схему: фонові міні-застосунки (аудіо, геолокація) — в окремому процесі з FOREGROUND_SERVICE, активні UI-міні-програми — в пулі WebView всередині основного процесу хоста з жорсткими обмеженнями через WebSettings.setJavaScriptEnabled та кастомний ContentProvider для міжпрограмного обміну даними. Порівняно з типовими single-process рішеннями, гібридний контейнер забезпечує у 2 рази менше крашів. Цей підхід знижує сукупну вартість володіння до 35% за рахунок зменшення кількості крашів та витрат на підтримку.
Як працює JavaScript Bridge?
Bridge — це протокол між JS-кодом міні-застосунку та нативними API хоста. Його дизайн визначає і можливості, і обмеження всієї екосистеми.
Типова реалізація на Android:
webView.addJavascriptInterface(new NativeBridge(context), "__miniapp_bridge__"); Але @JavascriptInterface у чистому вигляді небезпечний — будь-який JS у WebView отримує доступ до bridge. Тому поверх додаємо Origin Validator: кожен виклик bridge містить підписаний токен, згенерований при ініціалізації міні-застосунку та прив'язаний до його bundle hash.
На iOS використовуємо WKScriptMessageHandler:
configuration.userContentController.add(self, name: "miniAppBridge") З обов'язковою перевіркою message.frameInfo.isMainFrame — інакше iframe всередині міні-застосунку теж отримує доступ до нативних API.
Схема викликів асинхронна з correlation ID: JS відправляє {callId: uuid, method: "getLocation", params: {}}, нативна сторона резолвить проміс через webView.evaluateJavaScript("window.__resolve__('\(callId)', \(result))"). Тайм-аути — 5 секунд для звичайних викликів, 30 секунд для повільних (файлові операції, Bluetooth). Bridge latency зазвичай не перевищує 50 мс. 80% міні-застосунків використовують location API, що вимагає особливої уваги до дозволів.
Приклад реалізації bridge на Swift (скорочено)
class MiniAppBridge: NSObject, WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard message.frameInfo.isMainFrame else { return } // ... обробка виклику } } Керування життєвим циклом та пам'яттю
Життєвий цикл міні-застосунку: loading → active → background → suspended → destroyed. Контейнер слухає системні події пам'яті (onTrimMemory на Android, UIApplicationDidReceiveMemoryWarningNotification на iOS) та агресивно переводить фонові міні-програми з background у suspended (WebView заморожений, але контекст збережено) або destroyed (все скинуто, при наступному відкритті — холодний старт).
| Стан | Споживання RAM | Час відновлення |
|---|---|---|
| loading | ~50 MB | — |
| active | ~100 MB | — |
| background | ~80 MB (стиснуто) | <100 мс |
| suspended | ~20 MB | <300 мс |
| destroyed | 0 MB | 1.2 с (cold start) |
Типовий сценарій, який валить конкурентів: користувач відкрив 8 міні-застосунків підряд, не закриваючи. На iPhone з 4 GB RAM це ~1.6 GB лише під WebView-процеси. Система надсилає memory pressure notification, iOS вбиває кілька фонових процесів — і користувач бачить білий екран замість міні-застосунку. Наше рішення: моніторинг через os_proc_available_memory() (доступно з iOS 13), проактивне знищення suspended міні-програм при тиску >70%, та автоматичне відновлення стану через serialized snapshot перед знищенням. Після оптимізації споживання пам'яті знижується на 60%.
Безпека: capability-based розмежування доступу
Кожен міні-застосунок при реєстрації в маркетплейсі декларує permissions: ["location.read", "camera", "contacts.read"]. Контейнер зберігає approved permissions у зашифрованому сховищі (Keychain / Android Keystore) та валідує кожен bridge-виклик проти цього маніфесту. Спроба викликати незадекларований API — silent fail з логом в аналітику та прапорцем у системі моніторингу. Сертифіковане рішення повністю відповідає кращим практикам безпеки.
Що входить у роботу
- Аудит існуючої архітектури або проектування з нуля.
- Вибір моделі ізоляції (single/multi/hybrid).
- Проектування bridge API (зазвичай 2-4 тижні на узгодження, тому що це контракт з розробниками міні-застосунків).
- Реалізація runtime-контейнера.
- Навантажувальне тестування (100+ одночасних міні-застосунків у automated тесті).
- Інтеграція з marketplace та системою permissions.
- Підтримка та еволюція bridge API.
Терміни на контейнер «з нуля» під обидві платформи: від 3 до 6 місяців залежно від вимог до ізоляції, набору нативних API у bridge та наявності готових специфікацій. Тільки Android або тільки iOS — вдвічі швидше. Вартість проекту розраховується індивідуально, після оцінки обсягу. Наші клієнти економлять до 40% бюджету на підтримку завдяки проактивному моніторингу та гібридній архітектурі. Зв'яжіться з нами, щоб отримати консультацію по вашому проекту. Замовте розробку контейнера для вашого Super App — ми допоможемо з проектуванням та реалізацією.







