Реалізація міжпроцесного взаємодії міні-програм з основною додатком
Міні-програма живе в ізольованому контексті — свій WebView, своя пам'ять, потенційно свій процес. Але користувачу потрібно, щоб вона бачила баланс його гаманця в Super App, могла ініціювати замовлення таксі з іншої міні-програми, отримувала push-сповіщення через загальний канал хоста. Все це — міжпроцесне взаємодія (IPC). І тут архітектурні рішення мають прямі наслідки для безпеки всієї платформи.
Проблема: чому стандартний bridge недостатній
JS Bridge, описаний у контексті runtime-контейнера, вирішує завдання «міні-програма → нативний API хоста». Але IPC — це інші сценарії:
- Міні-програма → дані основної додатка: прочитати профіль користувача, баланс, історію замовлень
- Хост → міні-програма: відправити подію (змінився баланс, прийшло замовлення, змінилося стан сеансу)
-
Міні-програма A → міні-програма B: передати параметри при відкритті, повернути результат закриття (як
startActivityForResultна Android) - Міні-програма → фоновий сервіс хоста: запустити довготривалу операцію (завантаження файлу, background tracking)
Перша помилка — реалізувати все через один синхронний bridge-метод getData(key). Це створює data store всередину контейнера, до якого потенційно має доступ будь-яка міні-програма. Без суворої моделі дозволів будь-яке міні-програм читає дані будь-якого іншого.
Архітектура: Event Bus поверх bridge
Правильний підхід — типована система подій з namespace-ізоляцією:
// У SDK міні-програми
sdk.host.subscribe('wallet.balanceChanged', (payload) => {
updateUI(payload.balance)
})
sdk.host.emit('order.created', { items, total })
На нативній стороні це NotificationCenter (iOS) або LocalBroadcastManager / EventBus (Android) з proxy-шаром, який:
- Приймає emit від конкретної міні-програми
- Перевіряє, що міні-програма має дозвіл на цей event namespace
- Маршрутизує подію — либо всередину хоста, либо в іншу міні-програму
Маршрутизація між міні-програмами вимагає окремого рішення. Якщо вони у різних процесах — потрібна реальна IPC. На Android це Messenger + IBinder через AIDL, або у простіших випадках — ContentProvider як shared data bus. На iOS між процесами WKWebView — тільки через хост-додаток як посередника (Darwin notifications або XPC якщо WKWebView запущен в окремому Extension).
Паттерн Request-Response для міні-програма → міні-програма
Сценарій: міні-програма карт хоче відкрити міні-програму навігації та отримати назад вибраний маршрут.
На Android це аналог startActivityForResult, реалізований через контейнер:
// У міні-програмі карт
const route = await sdk.miniapp.open('com.maps.navigation', {
origin: currentLocation,
destination: selectedPoint
})
// route отримуємо коли navigation-міні-програма викличе sdk.miniapp.finish({route})
Контейнер зберігає correlation ID виклику, запускає цільову міні-програму з параметрами через deep link формат (miniapp://com.maps.navigation?callId=uuid¶ms=base64), і коли та викличе finish() — доставляє результат в промис викликуючої сторони.
Timeout на очікування результату — обов'язковий. Користувач може просто закрити навігаційну міні-програму не вибравши маршрут. Контейнер має резолвить промис з {cancelled: true} за 0ms при закритті.
Дані хоста: Scoped Data Access
Найбільш чутлива частина IPC — доступ міні-програм до даних основної додатка. Профіль користувача, платіжні дані, історія.
Реалізуємо через Data Provider API з явними scopes:
// Міні-програма запитує тільки те, що задекларувала у manifest
const user = await sdk.host.getUser(['name', 'phone', 'avatarUrl'])
// email та paymentMethods — недоступні без відповідного scope у manifest
На нативній стороні — Provider Registry: словник {scope → handler}. Кожен handler знає, для яких міні-програм він відкритий (можна обмежити білим списком bundle ID). Дані серіалізуються в JSON, передаються через bridge. Чутливі поля (токени, повні номери карт) — ніколи. Тільки токенізовані представлення.
Push-події від хоста до активної міні-програми
Хост отримав WebSocket-сповіщення про нове замовлення. Міні-програма кур'єра зараз відкрита. Потрібно сповістити її без користувацької дії.
На iOS: webView.evaluateJavaScript("window.__miniapp_dispatch__('\(eventJSON)')"). Це безпечно, якщо WebView уже у стабільному стані (після webView:didFinishNavigation:). До цього моменту — черга pending events, яка дренується після load complete.
На Android аналогічно через webView.evaluateJavascript(), але з перевіркою, що WebView не у PAUSED стані (інакше JS не виконуватиметься).
Для міні-програм у фоні — події ставляться в persistent queue та доставляються при наступному foreground. Критичні події (токен сеансу теч) — відправляються в системний notification канал хоста, який користувач бачить незалежно від стану міні-програми.
Ізоляція: що міні-програма НЕ повинна бачити
Міжпроцесний канал легко перетворюється на вектор атаки. Мінімальний набір обмежень:
- Міні-програма не знає список інших встановлених міні-програм (fingerprinting)
- Прямий доступ міні-програма → міні-програма тільки через хост-контейнер, ніколи прямо
- Payload подій логується (без чутливих даних) для аудиту
- Rate limiting на emit: не більше 100 подій в секунду від однієї міні-програми
Терміни реалізації IPC-підсистеми в рамках існуючого Super App з готовим контейнером: від 6 до 14 тижнів залежно від набору сценаріїв та вимог до безпеки. Повноцінна Event Bus + Scoped Data Access + Request-Response — ближче до старшої границі.







