Hybrid Development: Embedding Flutter in Native Apps (Add-to-App)
Enterprise-scale mobile applications often possess massive established native codebases. For these teams, a full rewrite is rarely feasible. Instead, they adopt Add-to-App, a modular integration strategy that allows Flutter to coexist within a native Android or iOS host, powering specific high-velocity features or new modules while maintaining the existing native infrastructure.
1. The Add-to-App Architecture
In a hybrid environment, the FlutterEngine is the brain of the integration. It is responsible for initializing the Dart VM, managing the rendering pipeline, and facilitating communication via Platform Channels.
- Hosting Mechanisms:
- Android: Flutter can be presented as a full-screen
FlutterActivityor a flexibleFlutterFragmentthat can be embedded into complex native layouts. - iOS: Flutter is presented via a
FlutterViewController.
- Android: Flutter can be presented as a full-screen
- Isolate Relationship: By default, one
FlutterEnginecorresponds to one Dart Isolate. If you need two Flutter screens to share data perfectly in real-time without channel overhead, they should share a single, "pre-warmed" engine.
2. Strategic "Engine Warm-up"
One of the primary challenges of hybrid development is "Startup Latency." Initializing a FlutterEngine takes approximately 100-200ms. If initiated only when the user clicks a button, it results in a jarring "White Screen" flicker.
The Solution: Pre-warming.
Bootstrap your FlutterEngine during the native application's startup phase (e.g., Application.onCreate in Android or didFinishLaunchingWithOptions in iOS). By the time the user reaches a Flutter-powered feature, the engine is already "warm," and the UI appears instantly.
3. PlatformView: The Reverse Integration
The inverse of Add-to-App is PlatformView—embedding a native view (like Google Maps or a platform-specific camera preview) directly inside the Flutter building-block hierarchy.
Hybrid Composition (The Modern Standard): Since Flutter 3.0, the "Hybrid Composition" model has become the standard for Android. It places the native view directly into the view hierarchy of the platform rather than rendering it to a texture.
- Superior Interaction: Handles native gestures, text selection, and keyboard focus more reliably than older methods.
- Performance Trade-off: Because it requires the native view and Flutter's Skia/Impeller layers to be composited by the system Window Manager, it is computationally more expensive than standard Flutter widgets.
4. Multi-Engine Scenarios
While most apps should aim for a single shared engine, complex apps might require multiple engines (e.g., a background engine for data sync and a foreground engine for UI).
- Memory Cost: Each
FlutterEngineadds roughly 15MB–30MB to the app's resident memory. - Synchronization: Engines do not share memory. If data updates in one engine, you must use a database (like SQLite) or a Platform Channel to inform the other engine.
5. Engineering Context: When to Go Hybrid?
Add-to-App is the ideal choice when:
- Iterative Migration: You are slowly transitioning a legacy app to Flutter.
- Shared Logic: You want to write a complex cross-platform business flow (like a multi-step checkout) once and use it in both your Android and iOS apps.
- High-Level Flexibility: You need to keep the native home screen for performance reasons but want the flexibility of Flutter for internal "content" pages.