Mini-App Container Implementation in Super App
When WeChat launched its mini-program platform in 2017, it became clear: a Super App is not just a large application, but an operating system layered on top of an operating system. The mini-app container is the most complex part of this architecture. It's not the mini-app logic itself, but the runtime shell that isolates them, launches them, and manages their lifecycle.
What is a Mini-App Container and Why It's Difficult to Build Right
A container is not simply a WebView with a URL. It's an isolation system, resource management, call marshaling to native APIs, and lifecycle control for each mini-app. Design errors lead to memory leaks between sessions, crash loops when switching apps, and security breaches — when one vendor's mini-app accesses another's data.
On Android, typical implementations build around isolated processes via android:process in the manifest, a custom ClassLoader per mini-app, and a custom WebViewClient intercepting all bridge:// URI requests. On iOS — WKWebView with a separate WKProcessPool per mini-app, isolated WKWebsiteDataStore, and hooks in WKScriptMessageHandler for native bridge calls.
The problem nearly everyone faces: memory budget. On 3-4 GB RAM devices, keeping 5-6 active WKWebView processes is infeasible. WeChat solved this through aggressive preloading of one empty WebView and a hot-standby pool of 2-3 initialized, but unloaded, instances. We use a similar approach adapted to the client's specific device matrix.
Runtime Isolation Architecture
The key decision: choosing between single-process and multi-process container models.
Single-process (everything in the host's process): simpler to implement, faster mini-app startup (no fork overhead), but any mini-app crash brings down the entire Super App. Suitable for closed ecosystems where trusted teams write mini-apps.
Multi-process (each mini-app in its own process): more stable, but on Android — an additional 30-50 MB RAM per process and 400-800 ms latency on first launch due to fork+zygote. On iOS, WKWebView processes are system-managed, making isolation de facto.
We implement a hybrid scheme: background mini-apps (audio, geolocation) in a separate process with FOREGROUND_SERVICE, active UI mini-apps in a WebView pool within the host process with strict limits via WebSettings.setJavaScriptEnabled and custom ContentProvider for inter-app data exchange.
JavaScript Bridge: The Container's Heart
The Bridge is the protocol between a mini-app's JS code and host native APIs. Its design determines both capabilities and limitations of the entire ecosystem.
Typical Android implementation:
webView.addJavascriptInterface(new NativeBridge(context), "__miniapp_bridge__");
But bare @JavascriptInterface is unsafe — any JS in the WebView gains bridge access. We add Origin Validator on top: each bridge call contains a signed token generated at mini-app initialization and bound to its bundle hash.
On iOS we use WKScriptMessageHandler:
configuration.userContentController.add(self, name: "miniAppBridge")
With mandatory message.frameInfo.isMainFrame checks — otherwise iframes within the mini-app also get native API access.
The call scheme is asynchronous with correlation IDs: JS sends {callId: uuid, method: "getLocation", params: {}}, the native side resolves the promise via webView.evaluateJavaScript("window.__resolve__('\(callId)', \(result))"). Timeouts: 5 seconds for normal calls, 30 seconds for slow ones (file operations, Bluetooth).
Lifecycle and Memory Management
A mini-app's lifecycle: loading → active → background → suspended → destroyed. The container listens to system memory events (onTrimMemory on Android, UIApplicationDidReceiveMemoryWarningNotification on iOS) and aggressively transitions background mini-apps from background to suspended (WebView frozen, context preserved) or destroyed (everything cleared, next open is a cold start).
A typical scenario that breaks competitors: user opens 8 mini-apps in sequence without closing. On iPhone 12 with 4 GB RAM this is ~1.6 GB for WebView processes alone. The system sends memory pressure: critical, iOS kills several background processes — and the user sees a blank screen instead of the mini-app. Our solution: monitor via os_proc_available_memory() (available since iOS 13), proactively destroy suspended mini-apps when pressure exceeds 70%, and automatically restore state via serialized snapshots before destruction.
Security: Capability-Based Access Control
Each mini-app declares permissions on marketplace registration: ["location.read", "camera", "contacts.read"]. The container stores approved permissions in encrypted storage (Keychain / Android Keystore) and validates each bridge call against this manifest. Attempts to call undeclared APIs fail silently with analytics logging and monitoring flags.
How It's Built
Audit existing architecture or design from scratch → choose isolation model → design bridge API (typically 2-4 weeks for alignment, as this is a contract with mini-app developers) → implement runtime container → load testing (100+ simultaneous mini-apps in automated tests) → integrate with marketplace and permissions system → support and evolve bridge API.
Timeline for a container from scratch on both platforms: 3 to 6 months depending on isolation requirements, native API breadth in bridge, and spec availability. Android or iOS only: twice as fast.







