Уявіть: маркетплейс із 50 партнерами, кожен хоче розмістити свій екран миттєво, без релізів в App Store. Керування цими модулями без шкоди безпеці та продуктивності — це виклик. Відповідь — система міні-програм. Ми розробляємо та впроваджуємо таку систему для Super App, забезпечуючи ізольоване виконання, безпечний доступ до нативних API та оновлення без релізу в App Store. Це не просто WebView-обгортка: ми будуємо повноцінну інфраструктуру, яка дозволяє партнерам створювати свої модулі, а хост-застосунку — контролювати кожен аспект їхньої роботи. Наша компанія має 8+ років досвіду в мобільній розробці та реалізувала понад 20 Super App проєктів, включаючи екосистеми для банків і маркетплейсів. Заміна моноліту на модульну архітектуру скорочує час виведення партнерського сервісу на 70%, а зниження вартості володіння сягає 30% за рахунок відсутності App Store рев'ю. Ми гарантуємо безпеку завдяки суворій системі дозволів та ізоляції. Оцінимо ваш проєкт за 2 дні — зв'яжіться для консультації. Орієнтовна вартість проєкту — від $40,000 залежно від складності.
Архітектура екосистеми вбудованих модулів
Два кардинально різних підходи до runtime.
WebView-based. Міні-програма — це веб-застосунок (React, Vue, або кастомний DSL як у WeChat WXML/WXSS). Запускається в ізольованому WKWebView (iOS) або WebView (Android). Стандартні веб-технології, низький поріг входу для партнерів, крос-платформеність коду міні-програми. Обмеження: продуктивність нижча за нативну, немає доступу до складних нативних API без Bridge.
Native plugin-based. Міні-програма — скомпільований нативний код (Android: DEX через DexClassLoader; iOS: compile-time Swift Package). Нативна продуктивність, повний доступ до API через контрольовані інтерфейси. Обмеження: App Store забороняє завантаження виконуваного коду на iOS, тому на iOS нативні плагіни мають бути включені в бінарник при збірці.
На практиці використовуємо гібрид: базові партнерські сервіси — WebView, власні критичні міні-програми — нативні плагіни. Нативний runtime кращий за WebView в 2–3 рази за швидкістю на складних UI-сценаріях. Порівняння підходів:
| Характеристика |
WebView-based |
Native plugin-based |
| Холодний старт |
500–800 мс |
100–200 мс |
| Доступ до API |
Тільки через Bridge |
Повний нативний |
| Оновлення |
Без релізу |
Без релізу (Android), з релізом (iOS) |
| Продуктивність UI |
Середня |
Висока |
WebView-based міні-програми простіші в розробці, але нативні плагіни в 2–3 рази швидші.
Формат пакета міні-програми
Міні-програма дистрибутується як zip-архів з маніфестом:
{
"id": "com.partner.loans",
"version": "2.3.1",
"minHostVersion": "3.0.0",
"entryPoint": "index.html",
"permissions": ["payment", "geolocation"],
"allowedDomains": ["api.partner.com", "cdn.partner.com"],
"signature": "sha256:abc123..."
}
При завантаженні хост верифікує підпис архіву (RSA-PSS з публічним ключем партнера), перевіряє сумісність minHostVersion, перевіряє permissions проти списку дозволених для даного партнера, розпаковує в ізольовану директорію. Запуск — тільки після успішної верифікації.
Як працює Bridge API?
Bridge — єдина точка контакту між міні-програмою та хостом. Архітектура запиту-відповіді:
На стороні міні-програми (JS):
MiniAppBridge.call('payment.pay', {
orderId: 'order-123',
amount: 99.99,
currency: 'USD'
}).then(result => {
// result.transactionId
}).catch(err => {
// err.code, err.message
});
На стороні хоста (нативний код) Bridge:
- Отримує виклик через
WKScriptMessageHandler.userContentController(_:didReceive:) (iOS) або @JavascriptInterface метод (Android)
- Парсить
method та params
- Перевіряє: чи є у цієї міні-програми дозвіл викликати
payment.pay
- Якщо так — виконує нативний код (показує Payment UI, обробляє транзакцію)
- Повертає результат через
webView.evaluateJavaScript("MiniAppBridge._resolve(requestId, result)")
Кожен метод Bridge має явний список дозволів. Виклик методу без потрібного дозволу -> синхронна помилка PERMISSION_DENIED. Дозволи видаються при реєстрації партнера, зберігаються на сервері, кешуються в хості.
Детальніше про компоненти Bridge
Bridge API складається з модулів: payment, auth, storage, geolocation, ui. Кожен модуль має власний набір дозволів. Наприклад, модуль payment вимагає дозволу payment, а модуль geolocation — geolocation. Документація доступна в Partner SDK.
Чому ізольоване сховище критичне?
Кожна міні-програма отримує namespace в локальному сховищі: ключі виду {mini_program_id}:{key}. Прямого доступу до SQLite або SharedPreferences хоста — немає. Доступ тільки через Bridge методи storage.set / storage.get / storage.remove з примусовим namespace.
WebView localStorage теж ізольований: кожна міні-програма запускається з WKWebViewConfiguration з окремим WKWebsiteDataStore.nonPersistent() або іменованим persistent store. На Android — WebStorage з кастомним директорієм та забороною перетину origin.
Сесія користувача. Міні-програма отримує access token тільки через Bridge auth.getToken(). Токен видається хостом на 15 хвилин, прив'язаний до mini_program_id, scope обмежений. Міні-програма не бачить master JWT користувача.
Як оновлюються міні-програми?
Оновлення — без рев'ю в App Store. Послідовність:
- При запуску міні-програми (або у фоні за розкладом) хост перевіряє актуальну версію через
GET /mini-programs/{id}/version
- Якщо сервер повертає новішу версію — завантажуємо архів у фоні
- Верифікуємо підпис нового архіву
- При наступному запуску міні-програми — активуємо новий пакет
- Попередня версія — в backup (для rollback при необхідності)
Примусове оновлення: якщо minHostVersion нового пакета несумісна з поточним хостом — показуємо екран Доступне оновлення застосунку замість запуску міні-програми.
Налагодження та DevTools для партнерів
Розробнику міні-програми потрібен зручний інструментарій. Надаємо:
- Simulator mode: локальний сервер (
localhost:8080) як джерело міні-програми замість CDN — хост читає файли напряму без верифікації підпису (тільки в debug build)
- Bridge Inspector: логування всіх Bridge-викликів у debug консоль Xcode / Android Studio Logcat
- Mock Bridge: JS-бібліотека (
mini-program-bridge-mock) для тестування в браузері без хоста
Кейс. Партнерська екосистема маркетплейсу: 8 партнерів, 23 активних міні-програми (12 WebView, 11 нативних плагінів на Android / compile-time на iOS). Bridge API: 55 методів. Середній час холодного запуску міні-програми (перший за сесію) — 380 мс на iPhone 14. Теплий запуск (повернення після паузи) — 80 мс. Оновлення у фоні: 70% користувачів отримують нову версію міні-програми без перезапуску хоста. Впровадження системи дозволило збільшити конверсію на 15% та знизити вартість інтеграції на 40%.
Що входить у роботу
- Аналіз вимог та проектування Bridge API
- Реалізація WebView- та нативного runtime
- Інтеграція з CDN, підпис пакетів та система оновлень
- DevTools для партнерів: Simulator, Inspector, Mock
- Документація та навчання команди партнера
- Підтримка після запуску
Орієнтовні терміни
| Компонент |
Терміни |
| WebView runtime + базовий Bridge (20 методів) |
8–12 тижнів |
| Маркетплейс + підпис + оновлення |
+4–6 тижнів |
| Нативний plugin runtime (Android) |
+4–8 тижнів |
| Partner SDK + DevTools |
+4–6 тижнів |
Вартість розраховується індивідуально після аналізу вимог до Bridge API, кількості партнерів та вимог безпеки. Зв'яжіться для точної оцінки вашого проєкту. Отримайте консультацію — ми підберемо оптимальну архітектуру.
Super app
MVVM, Clean Architecture, BLoC, VIPER, TCA: проєктуємо архітектуру під ключ
Додаток зібрано в одному ViewController на 2000 рядків. Мережеві виклики, бізнес-логіка, оновлення UI — все в одному місці. Додати нову фічу без регресії складно, написати тест неможливо. Це не «поганий код» — це відсутність архітектури. І це трапляється частіше, ніж можна очікувати, навіть у production-додатках з мільйоном користувачів.
Ми проєктуємо архітектуру під ключ: від вибору паттерну до повної структури проєкту з тестами та документацією. За 7–10 днів отримуєте чистий модульний код, готовий до масштабування. Ваша команда зможе додавати нові фічі без ризику зламати існуючі, а тести покриють ключову логіку вже на старті. Архітектурні паттерни в мобайлі вирішують одне завдання: відокремити UI від логіки так, щоб кожна частина була тестованою та замінною.
MVVM — базовий паттерн
Model-View-ViewModel — стандарт для iOS (SwiftUI + Combine/async, UIKit + Combine) та Android (Jetpack ViewModel + StateFlow + Compose). ViewModel містить стан UI та бізнес-логіку. View лише відображає стан і передає наміри користувача до ViewModel. Model — дані та їх джерело.
Ключове правило: ViewModel не знає про UIKit або Android View-класи. Немає імпортів UIKit, немає Context-залежностей (крім Application context через Hilt). Це гарантує тестованість: ViewModel тестується як чистий Kotlin/Swift-код без Android Instrumented Test.
MVVM закриває 70% потреб. Інші 30% — де потрібна строга ізоляція фіч, масштабування команди, складний flow управління станом.
Clean Architecture — коли MVVM недостатньо
Додає шари поверх MVVM:
Domain-шар — бізнес-логіка, незалежна від платформи. UseCase (або Interactor) містить одне бізнес-правило: GetUserOrdersUseCase, PlaceOrderUseCase. Залежить лише від інтерфейсів (protocol/interface), не від конкретних реалізацій.
Data-шар — реалізація репозиторіїв. OrderRepositoryImpl реалізує OrderRepository з domain. Знає про Retrofit, Room, UserDefaults. ViewModel не знає, звідки дані — з мережі чи кешу.
Presentation-шар — ViewModel + View. Знає про Domain, не знає про Data.
Dependency rule: залежності спрямовані лише всередину. Domain не залежить ні від чого. Data та Presentation залежать від Domain.
Presentation → Domain ← Data
Це дає можливість підміняти реалізацію: тест використовує in-memory репозиторій замість мережевого, інтерфейс залишається тим самим.
Практичне зауваження: Clean Architecture додає файли та шари. Для невеликого додатку це overhead. Виправдано від ~15 фіч та при команді 3+ розробників.
BLoC для Flutter — передбачуваний потік станів
BLoC (Business Logic Component) — стандартний паттерн у Flutter-спільноті. Бібліотека flutter_bloc реалізує його через два типи: Bloc (Event → State) та Cubit (State без Events, лише методи).
Bloc обробляє Event та емітує новий State через on<EventType> хендлери. Стан імутабельний — новий об'єкт на кожну зміну. BlocBuilder перемальовує лише ту частину дерева, де змінився state.
// Подія
alias CartEvent {}
class AddItemToCart extends CartEvent {
final String productId;
AddItemToCart(this.productId);
}
// Стан
alias CartState {}
class CartLoaded extends CartState {
final List<CartItem> items;
CartLoaded(this.items);
}
// Bloc
class CartBloc extends Bloc<CartEvent, CartState> {
CartBloc(this._cartRepository) : super(CartLoaded([])) {
on<AddItemToCart>(_onAddItem);
}
Future<void> _onAddItem(AddItemToCart event, Emitter<CartState> emit) async {
final current = state as CartLoaded;
final updated = await _cartRepository.addItem(event.productId);
emit(CartLoaded(updated));
}
}
Перевага BLoC — тестованість. blocTest з bloc_test пакету дозволяє перевірити: при такому-то Event, з таким-то початковим State, BLoC має емітувати такий-то State. Без UI, без моків для Flutter-фреймворку.
VIPER — для великих iOS-проєктів
VIPER (View, Interactor, Presenter, Entity, Router) — найбільш строгий поділ обов'язків для iOS. Кожен компонент має протокол та конкретну реалізацію.
- View — лише UI, делегує все Presenter
- Interactor — бізнес-логіка, робота з мережею та даними
- Presenter — посередник між View та Interactor, форматує дані для View
- Entity — моделі даних (чисті структури)
- Router — навігація між модулями
Кожен модуль (екран або фіча) — окремий VIPER-модуль. Це виключає coupling між фічами та дозволяє великим командам працювати паралельно без конфліктів.
Ціна: багато файлів, багато протоколів. Шаблонний код генерується через Sourcery або кастомні Xcode-шаблони. VIPER виправданий для додатків з 10+ розробниками та 50+ екранами.
TCA (The Composable Architecture)
TCA від Point-Free — більш сучасна альтернатива VIPER для iOS/macOS. Основні концепції: State (імутабельний стан фічі), Action (всі можливі події), Reducer (State + Action → новий State + Effect), Store (зберігає State, обробляє Actions).
Scope дозволяє composable будувати великі фічі з маленьких: батьківський Reducer делегує частину State дочірньому. Кожна фіча тестується ізольовано через TestStore з точним контролем над Effects.
TCA має круту криву навчання, але дає передбачуваність, яку складно отримати іншим способом: кожна зміна стану — явний Action з конкретним джерелом.
Як обрати архітектуру мобільних додатків?
Оцінимо проєкт за 1 день — підберемо архітектуру з урахуванням розміру команди, платформи та планів зростання.
| Паттерн |
Платформа |
Команда |
Коли обирати |
| MVVM |
iOS, Android, Flutter |
1–5 |
Стартовий стандарт, MVP, невеликі проєкти |
| MVVM + Clean |
iOS, Android |
3–10 |
Середні проєкти, тестованість критична |
| BLoC |
Flutter |
2–8 |
Flutter з передбачуваним state management |
| VIPER |
iOS |
5–20 |
Великі iOS-проєкти, модульна архітектура |
| TCA |
iOS/macOS |
3–15 |
Сувора тестованість, Swift Concurrency |
Універсальної відповіді немає. Архітектуру обирають під розмір команди, вимоги до тестованості та горизонт підтримки додатку.
Що входить у нашу роботу
Процес складається з кількох кроків:
-
Аудит поточної архітектури (якщо додаток вже існує) — виявимо вузькі місця та регресійні зони.
-
Проєктування модульної структури з чіткими межами шарів та правилами залежностей.
-
Створення каркасу проєкту (Scaffold) з впровадженням DI, організації папок та налаштування лінтерів.
-
Написання юніт-тестів для шару домену та ViewModel — мінімум 80% покриття ключових use case.
-
Підготовка документації — архітектурні діаграми, README з правилами модифікації коду, інструкція для онбордингу нових розробників.
-
Передача робочого репозиторію з CI-пайплайном (GitHub Actions / Bitrise), налаштованим запуском тестів та статичним аналізом.
Все це входить у вартість проєктування. Додатково — підтримка на етапі впровадження: консультації команди, code review перших pull request.
Що відбувається без архітектури
Типовий сценарій через 18 місяців без архітектури: 40% часу розробки йде на дебаг регресій. Новий розробник розбирається в коді тиждень перед тим, як зробити перший PR. Тести не пишуться, «тому що складно мокувати». Додавання нової фічі вимагає розуміння половини кодової бази.
Вибір архітектури на старті — це інвестиція з поверненням через 3–6 місяців. За нашими даними, правильно спроєктована архітектура з MVVM + Clean дає в 3 рази менше регресій порівняно з монолітним ViewController. А витрати на її впровадження окупаються за 2–3 спринти. Середня економія на усуненні дефектів після впровадження — до 40% часу, що для команди з п'яти осіб може означати понад 10 000 доларів на рік.
Згідно з рекомендаціями Apple щодо проєктування додатків, розділення обов'язків — ключовий фактор стійкості коду.
Чому варто довірити архітектуру професіоналам?
Неправильний вибір паттерну на старті веде до переписування половини коду через рік. Ми бачили десятки проєктів, де спроба заощадити на архітектурі оберталася багатомісячним рефакторингом. У нас за плечима 10+ років комерційної розробки, досвід роботи з додатками від 1 до 50 розробників, понад 100 успішно реалізованих проєктів. Ми допомагаємо уникнути типових помилок:
- Overengineering для простого MVP (призначаємо MVVM, а не VIPER).
- Відсутність dependency injection — підключаємо Hilt/Koin/Dagger вже на старті.
- Ігнорування тестованості — закладаємо протоколи/інтерфейси з першого коміту.
Зв'яжіться з нами через Telegram або email — отримайте безкоштовну оцінку вашого проєкту та рекомендацію щодо оптимальної архітектури. Замовте проєктування вже сьогодні — і за тиждень стартуйте з чистим, масштабованим кодом.
Додаткова таблиця: порівняння витрат на впровадження
| Паттерн |
Час проєктування |
Кількість файлів на 1 екран |
Час написання тестів |
| MVVM |
2–3 дні |
5–7 |
1 день |
| MVVM + Clean |
4–5 днів |
10–12 |
2 дні |
| BLoC |
3–4 дні |
6–8 |
1.5 дня |
| VIPER |
5–7 днів |
12–15 |
2.5 дня |
| TCA |
5–6 днів |
8–10 |
2 дні |
Час вказано для команди з 2–3 розробників. З нашим шаблоном (generator) стартовий каркас готовий за 1 день незалежно від обраного паттерну.