Integrating Platform-Specific Code in Flutter
Contents
Core Concepts & Terminology
- FFI (Foreign Function Interface): The library used to bind Dart directly to native C/C++ APIs.
- Platform Channel: The asynchronous message-passing system (, ) connecting the Dart client (UI) to the host platform (Kotlin/Java, Swift/Objective-C, C++).
- Pigeon: A code-generation tool that creates type-safe Platform Channels.
- Platform View: A mechanism to embed native UI components (e.g., Android , iOS ) directly into the Flutter widget tree.
- JS Interop: The modern, Wasm-compatible approach to interacting with JavaScript and DOM APIs using and .
Binding to Native C/C++ Code (FFI)
Use FFI to execute high-performance native code or utilize existing C/C++ libraries without the overhead of asynchronous Platform Channels.
Project Setup
- If creating a standard C/C++ integration (Recommended since Flutter 3.38): Use the template. This utilizes hooks to compile native code, eliminating the need for OS-specific build files (CMake, build.gradle, podspec).
bash
flutter create --template=package_ffi <package_name>
- If requiring access to the Flutter Plugin API or Play Services: Use the legacy template.
bash
flutter create --template=plugin_ffi <plugin_name>
Implementation Rules
- Symbol Visibility: Always mark C++ symbols with and prevent linker discarding during link-time optimization (LTO).
cpp
extern "C" __attribute__((visibility("default"))) __attribute__((used))
- Dynamic Library Naming (Apple Platforms): Ensure your hook produces the exact same filename across all target architectures (e.g., vs ) and SDKs ( vs ). Do not append architecture suffixes to the or names.
- Binding Generation: Always use to generate Dart bindings from your C headers (). Configure this in .
Implementing Platform Channels & Pigeon
Use Platform Channels when you need to interact with platform-specific APIs (e.g., Battery, Bluetooth, OS-level services) using the platform's native language.
Pigeon (Type-Safe Channels)
Always prefer
over raw
implementations for complex or frequently used APIs.
- Define the messaging protocol in a standalone Dart file using Pigeon annotations ().
- Generate the host (Kotlin/Swift/C++) and client (Dart) code.
- Implement the generated interfaces on the native side.
Threading Rules
- Main Thread Requirement: Always invoke channel methods destined for Flutter on the platform's main thread (UI thread).
- Background Execution: If executing channel handlers on a background thread (Android/iOS), you must use the Task Queue API (
makeBackgroundTaskQueue()
).
- Isolates: To use plugins/channels from a Dart background , ensure it is registered using
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken)
.
Hosting Native Platform Views
Use Platform Views to embed native UI components (e.g., Google Maps, native video players) into the Flutter widget tree.
Android Platform Views
Evaluate the trade-offs between the two rendering modes and select the appropriate one:
- If requiring perfect fidelity, accessibility, or SurfaceView support: Use Hybrid Composition ( + ). This appends the native view to the hierarchy but may reduce Flutter's rendering performance.
- If prioritizing Flutter rendering performance and transformations: Use Texture Layer (). This renders the native view into a texture. Note: Quick scrolling may drop frames, and is problematic.
iOS Platform Views
- iOS exclusively uses Hybrid Composition.
- Implement
FlutterPlatformViewFactory
and in Swift or Objective-C.
- Use the widget on the Dart side.
- Limitation: and widgets cannot be applied to iOS Platform Views.
Integrating Web Content & Wasm
Flutter Web supports compiling to WebAssembly (Wasm) for improved performance and multi-threading.
Wasm Compilation
- Compile to Wasm using: .
- Server Configuration: To enable multi-threading, configure your HTTP server to emit the following headers:
Cross-Origin-Embedder-Policy: credentialless
(or )
Cross-Origin-Opener-Policy: same-origin
- Limitation: WasmGC is not currently supported on iOS browsers (WebKit limitation). Flutter will automatically fall back to JavaScript if WasmGC is unavailable.
Web Interop
- If writing new web-specific code: Strictly use and .
- Do NOT use: , , or . These are incompatible with Wasm compilation.
- Embedding HTML: Use
HtmlElementView.fromTagName
to inject arbitrary HTML elements (like ) into the Flutter Web DOM.
Workflows
Workflow: Creating a Native FFI Integration
Use this workflow when binding to a C/C++ library.
Workflow: Implementing a Type-Safe Platform Channel (Pigeon)
Use this workflow when you need to call Kotlin/Swift APIs from Dart.
Workflow: Embedding a Native Platform View
Use this workflow when embedding a native UI component (e.g., a native map or camera view).