⚡ Sangsakala Proxy 🏠 Home
Skip to main content

Native interop

Learn about the options to call platform-specific code in your app.

Flutter apps run on multiple platforms, but sometimes you need to communicate directly with the host operating system or run code from an existing native library.

To solve this, Flutter provides several interop tools ranging from code generators to direct FFI bindings.

Use the following decision tree to choose your interop solution, or read on to learn about the native interop layers.

Choose your interop solution

#
No (most common)Yes (advanced)Question 1: What is yourprimary goal?Goal A: Platform integration(Swift, Kotlin, Java, Obj-C)Goal B: C-ABI wrapping(C, C++, Rust, Go)Goal C: Pure Dart package(No Flutter framework)Use FFIgen(or Flutter Rust Bridge)Use FFIgen or JNIgenQuestion 2: Do high-complexityconstraints apply?Use Pigeon(Recommended default)Use FFIgen or JNIgen
No (most common)Yes (advanced)Question 1: What is yourprimary goal?Goal A: Platform integration(Swift, Kotlin, Java, Obj-C)Goal B: C-ABI wrapping(C, C++, Rust, Go)Goal C: Pure Dart package(No Flutter framework)Use FFIgen(or Flutter Rust Bridge)Use FFIgen or JNIgenQuestion 2: Do high-complexityconstraints apply?Use Pigeon(Recommended default)Use FFIgen or JNIgen

Answer the following questions to walk through the decision tree in detail:

Question 1: What is your primary goal?

#
Goal A: Platform integration

Communicate with native OS features (Swift, Kotlin, Java, or Objective-C) or expose an API surface. Proceed to Question 2: Do high-complexity constraints apply?.

Goal B: C-ABI wrapping

Wrap an existing native library (C, C++, Rust, or Go). Use FFIgen (or Flutter Rust Bridge for Rust).

Goal C: Pure Dart package

Build a Dart CLI tool without Flutter framework dependencies. Use FFIgen or JNIgen.

Question 2: Do high-complexity constraints apply?

#

If you're building a Flutter plugin, first verify whether Pigeon satisfies your technical constraints.

Do any of the following requirements apply to your feature?

  • Your app processes high-frequency raw data (for example, video processing).
  • Your integration requires advanced language bridging (for example, cross-language subclasses, delegates, or proxies).
  • Your feature requires manual memory management and multithreading over guardrails.
  • Your target language is C, C++, Rust, or Go.

Based on whether any of the preceding requirements apply, choose your interop tool:

No (most common) — Use Pigeon

This is the default, recommended path. It provides necessary guardrails, creates easily digestible interface mappings, and is highly efficient for most API surface areas.

Yes — Use FFIgen or JNIgen

You need the flexibility, complexity, and performance of direct interop for larger surface areas.

Package your interop code

#

Depending on how you plan to share your code, choose the option that best suits your use case. To learn about the difference between a packagePackageAt a minimum, a Dart package is a directory containing a `pubspec.yaml` file. Learn more and a pluginPluginA plugin package (generally referred to as _a plugin_), is a special kind of package that makes platform functionallity available to the app. Learn more, refer to the Flutter glossary.

  • In-app integration. Write your native interop code directly inside your Flutter app without creating a separate package.
  • Plugin. A specialized package that makes native platform functionality (such as a device's camera or sensors) available to your app (flutter create --template=plugin). For more details, refer to Developing plugin packages.
  • FFI package. A package that compiles and bundles native C or C++ code (or pre-compiled binaries) using Dart build hooks and dart:ffi. This template also includes an FFIgen configuration to regenerate Dart bindings (flutter create --template=package_ffi). For more details, refer to Developing FFI packages.

For more details on package authoring, refer to Developing packages and plugins.

Tool comparison

#

The following table compares two interop solutions:

  • Direct interop: Lower-level direct bindings with higher performance for large data; requires manual memory and threading management.
  • Pigeon: Structured, type-safe code generator; recommended default for Flutter plugins.
Target languageDirect interopPigeon
C FFIgen Supported on Linux (GObject) with platform channels
C++ with extern "C" FFIgen Supported on Windows with platform channels
C++ without extern "C" FFIgen (not yet supported) Supported on Windows with platform channels
Rust with extern "C" FFIgen Not supported directly
Rust without extern "C" Flutter Rust Bridge Not supported
Go with extern "C" FFIgen Not supported directly
Go without extern "C" Not supported Not supported
Java JNIgen Supported through Kotlin (native interop) or directly with platform channels
Kotlin JNIgen Supported (recommended)
Objective-C FFIgen Supported through Swift (native interop) or directly with platform channels
Swift without Obj-C compatibility annotations package:swiftgen (experimental) Supported (recommended)

Understand interop layers

#

Dart structures native interop into three distinct layers: low-level bindings, idiomatic Dart APIs, and framework-specific plugins.

For complete architectural details, consult the native interop layers guide.

Layer 1: Low-level bindings

#

Layer 1 consists of thin, high-performance, and unopinionated wrappers around native code (for example, dart:ffi, dart:js_interop, FFIgen, and JNIgen). These APIs mirror native signatures closely, but require manual memory and threading management.

Layer 2: Idiomatic Dart APIs

#

Layer 2 consists of idiomatic Dart APIs that wrap the low-level layer to hide platform-specific complexities (for example, Pigeon or the sqlite3 package). These manage concurrency, memory lifetimes, and data conversions automatically.

Layer 3: Framework-specific plugins

#

Layer 3 provides integration with framework-specific APIs (for example, the Flutter Plugin API). This layer exposes Dart APIs to the framework while hiding platform details like Android's Context or iOS's application lifecycle.