skip to content

In Flutter's add-to-app, what is a Flutter module, and how does an existing Android or iOS app show one Flutter screen from it?

level: juniorimportance: should knowfreq 32%

answer

  1. flutter create -t module
  2. host app keeps its own navigation
  3. FlutterActivity declared in the manifest
  4. FlutterViewController on iOS
  5. implicit engine means a startup delay

basics

~20 s

A Flutter module is a Flutter project built to be embedded in an existing native app. Android launches it through FlutterActivity (or FlutterFragment), iOS through a FlutterViewController; each runs the module's Dart entrypoint in a FlutterEngine.

solid answer

~40 s

Add-to-app embeds Flutter piecemeal in a native app. On Android you create a module with `flutter create -t module --org com.example loyalty_module`, wire it into the Gradle build (or ship it as an AAR with `flutter build aar`), declare `io.flutter.embedding.android.FlutterActivity` in `AndroidManifest.xml`, and start it with `FlutterActivity.withNewEngine().initialRoute("/loyalty").build(context)` or `createDefaultIntent`. On iOS (Flutter 3.44+), `flutter build swift-package --platform ios` produces Swift packages the Xcode project adds, and you present a `FlutterViewController`. Without a pre-warmed engine, each screen creates its own `FlutterEngine`, which works but shows a noticeable delay before the first frame; the Flutter screen keeps its own navigation stack while the host app keeps the rest.

go deeper

for a junior

Recall that a Flutter module is embedded in a native app and shown through FlutterActivity or FlutterFragment on Android and FlutterViewController on iOS.

for a middle

Explain the module layout, the manifest entry, launching with an initial route, and why an implicit engine causes a first-frame delay.

for a senior

Plan the build integration per platform, including SwiftPM on iOS since 3.44, and the limits such as one module per app and AndroidX-only hosts.

for a principal

Decide which features of a native app to move to Flutter first, weighing engine cost, team boundaries and the long-term migration path.

## What add-to-app is Rewriting a large native app is rarely practical. **Add-to-app** lets a team render part of an existing Android or iOS app with Flutter — for example a new loyalty-points screen inside a native airline app — while everything else stays native. On mobile, Flutter runs as **multi-engine** add-to-app: each Flutter instance is a separate Dart program in its own `FlutterEngine`. ## The Flutter side: a module A **Flutter module** is a Flutter project whose purpose is to be embedded: ```bash flutter create -t module --org com.example loyalty_module ``` - It has the usual `lib/main.dart` and `pubspec.yaml`, and can depend on plugins. - Its Android and iOS host projects live in hidden `.android/` and `.ios/` folders that the tool generates; the real host is your existing app. - You can still `flutter run` it on its own for fast iteration, and attach to it from the host with `flutter attach` for hot reload. For iOS on Flutter 3.44 and later, the docs recommend starting a first integration from a normal Flutter **application**, and integrating either kind through Swift Package Manager. ## Wiring it into the host | Step | Android | iOS | |---|---|---| | Build integration | Gradle source dependency, or an AAR from `flutter build aar` | Swift packages from `flutter build swift-package --platform ios` | | UI container | `FlutterActivity` (full screen) or `FlutterFragment` (part of a screen) | `FlutterViewController` | | Registration | Declare `io.flutter.embedding.android.FlutterActivity` in `AndroidManifest.xml` | Add the generated Swift packages to the app target | | Launch | `startActivity(FlutterActivity.createDefaultIntent(this))` | `present(FlutterViewController(project: nil, nibName: nil, bundle: nil), animated: true)` | On Android, the intent builder also sets the initial route: ```kotlin startActivity( FlutterActivity .withNewEngine() .initialRoute("/loyalty") .build(this) ) ``` (The Gradle wiring and Podfile-based integration have their own topics; the older CocoaPods and `flutter build ios-framework` integrations are legacy paths in 3.47.) ## What happens at launch 1. The container creates a **`FlutterEngine`** implicitly, because none was provided. 2. The engine finds and loads Flutter's libraries, starts the Dart VM on first use, creates an isolate and runs `main()` (or a named entrypoint). 3. The container gives the engine a rendering surface, and the first frame appears. This implicit engine is the simplest setup, but it has a **non-trivial warm-up time**, so users see a brief blank delay each time. The fix — pre-warming and caching an engine — is the next step most teams take. ## Things interviewers check - The Flutter screen keeps its **own navigation stack**; the host's back stack and Flutter's `Navigator` are separate. - Data crosses between the native app and Flutter through **platform channels** (or Pigeon), not shared memory. - Plugins work in a module, but plugins that assume a Flutter `Activity` is always present can misbehave. - On Android, the module requires an **AndroidX** host app. - Packing **multiple Flutter modules** (libraries) into one app is not supported; one module can serve many screens. ## Common misconceptions - A module is not a plugin: plugins add native code to Flutter apps, a module adds Flutter to a native app. - Add-to-app does not require converting the host's navigation or build system wholesale. - Showing Flutter does not need a pre-warmed engine; pre-warming is an optimisation, not a requirement.

  • What is the difference between FlutterActivity.createDefaultIntent and withNewEngine?
    Both make `FlutterActivity` create its own engine. `createDefaultIntent(context)` uses the defaults — the default route and entrypoint — while `withNewEngine()` returns a builder where you can set `initialRoute`, the Dart entrypoint or the background mode before calling `build(context)`.
  • Can an app embed two different Flutter modules for two teams?
    No: packing multiple Flutter libraries into one application is not supported on mobile. Teams share one module, possibly with several entrypoints or routes, and the host can show several Flutter screens from it.

saying these in an interview costs you the question

  • A Flutter module is the same thing as a Flutter plugin package.
  • Add-to-app requires rewriting the host app's navigation in Flutter.
  • FlutterActivity works without being declared in AndroidManifest.xml.
  • The host app and the Flutter screen share one navigation stack.
  • A pre-warmed engine is required before any Flutter screen can appear.