Resources
Resources
July 2, 2025

Integrate Flutter into Your Native App with Add-to-App (Without a Full Rewrite)

Integrating Flutter into an existing native app might sound like a complex decision, but in practice, it's a powerful way to modernize your UI, iterate faster, and bring consistency across platforms — all without rewriting your whole codebase.

In this post, we'll walk through how to use Flutter as a module inside native Android and iOS apps using Flutter Add-to-App. We'll also show how to use GoRouter for navigation and Pigeon to bridge native and Dart logic in a type-safe, scalable way.

Why Add-to-App?

Flutter is great, but not every team is ready for a full rewrite — and you shouldn’t have to be. With Add-to-App:

  • You can incrementally adopt Flutter in high-impact areas
  • Developers can experiment without affecting the native app core
  • You can build new UI with Flutter’s speed and flexibility
  • You get native performance and Flutter UI where it makes sense

Setting up a Flutter Module

Start by creating a new Flutter module:

flutter create --template module flutter_module

This creates a structure optimized for embedding. Inside this module, we recommend:

  • Using go_router to manage navigation cleanly
  • Defining native-Dart interfaces using pigeon for clean, boilerplate-free platform channels

Android Integration

Link the module in `settings.gradle`:

include ':flutter'
setProjectDir(':flutter', file('../flutter_module'))

Add it to `app/build.gradle`:

dependencies {
  implementation project(':flutter')
}

Start a Flutter screen from your activity:

startActivity(
  FlutterActivity
    .withNewEngine()
    .initialRoute("/qr")
    .build(this)
)

For production, consider caching a single engine instance to improve launch time.

iOS Integration

In your iOS project’s `Podfile`:

flutter_application_path = '../flutter_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
install_all_flutter_pods(flutter_application_path)

Then:

pod install

Launching Flutter from Swift:

let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterVC = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
flutterVC.setInitialRoute("/qr")
present(flutterVC, animated: true)

4. Navigation with GoRouter

Inside your Flutter module:

final router = GoRouter(
  routes: [
    GoRoute(
      path: '/qr',
      builder: (context, state) => const QrScannerScreen(),
    ),
  ],
);

Then plug it into your `MaterialApp.router`:

MaterialApp.router(
  routerConfig: router,
)

This makes your screens deep-linkable and easy to coordinate from native.

5. Communication with Pigeon

Pigeon helps you generate type-safe messaging code between Dart and platform code.

Define your interface:

@HostApi()
abstract class QrApi {
  String sendResult(String scannedCode);
}

Generate code for both platforms:

flutter pub run pigeon \
  --input pigeons/api.dart \
  --dart_out lib/pigeon/api.g.dart \
  --kotlin_out android/app/src/main/kotlin/com/yourcompany/QrApi.kt     
  --swift_out ios/Runner/QrApi.swift

Implement in native code (e.g. Kotlin):

class QrApiImpl : QrApi {
    override fun sendResult(scannedCode: String): String {
        Log.d("QR", "Received: $scannedCode")
        return "Success"
    }
}

Then register it:

QrApi.setUp(flutterEngine.dartExecutor.binaryMessenger, QrApiImpl())

Final Thoughts

Add-to-App isn’t just for transitional phases. It’s a powerful long-term architecture for hybrid teams and projects that need the best of both worlds.

With tools like Pigeon and GoRouter, integrating Flutter doesn’t just feel native — it is native. And once you're up and running, your team can start shipping faster with a consistent experience across platforms.

Whether you’re shipping a single screen or planning a larger migration, Flutter Add-to-App is ready when you are.

Pro tip: Reuse a single Flutter engine when possible and preload it early to improve performance on first navigation.

Written by Juan Garcia da Rosa, Senior Engineer at Leenspace.

Happy hybrid coding! 🚀