flutter-interoperating-with-native-apis
Integrating Platform-Specific Code in Flutter
Contents
- Core Concepts & Terminology
- Binding to Native C/C++ Code (FFI)
- Implementing Platform Channels & Pigeon
- Hosting Native Platform Views
- Integrating Web Content & Wasm
- Workflows
Core Concepts & Terminology
- FFI (Foreign Function Interface): The
dart:ffilibrary used to bind Dart directly to native C/C++ APIs. - Platform Channel: The asynchronous message-passing system (
MethodChannel,BasicMessageChannel) 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
View, iOSUIView) directly into the Flutter widget tree. - JS Interop: The modern, Wasm-compatible approach to interacting with JavaScript and DOM APIs using
package:webanddart:js_interop.
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
package_ffitemplate. This utilizesbuild.darthooks to compile native code, eliminating the need for OS-specific build files (CMake, build.gradle, podspec).flutter create --template=package_ffi <package_name> - If requiring access to the Flutter Plugin API or Play Services: Use the legacy
plugin_ffitemplate.flutter create --template=plugin_ffi <plugin_name>
Implementation Rules
- Symbol Visibility: Always mark C++ symbols with
extern "C"and prevent linker discarding during link-time optimization (LTO).extern "C" __attribute__((visibility("default"))) __attribute__((used)) - Dynamic Library Naming (Apple Platforms): Ensure your
build.darthook produces the exact same filename across all target architectures (e.g.,arm64vsx86_64) and SDKs (iphoneosvsiphonesimulator). Do not append architecture suffixes to the.dylibor.frameworknames. - Binding Generation: Always use
package:ffigento generate Dart bindings from your C headers (.h). Configure this inffigen.yaml.
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 package:pigeon over raw MethodChannel implementations for complex or frequently used APIs.
- Define the messaging protocol in a standalone Dart file using Pigeon annotations (
@HostApi()). - 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
Isolate, ensure it is registered usingBackgroundIsolateBinaryMessenger.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 (
PlatformViewLink+AndroidViewSurface). 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 (
AndroidView). This renders the native view into a texture. Note: Quick scrolling may drop frames, andSurfaceViewis problematic.
iOS Platform Views
- iOS exclusively uses Hybrid Composition.
- Implement
FlutterPlatformViewFactoryandFlutterPlatformViewin Swift or Objective-C. - Use the
UiKitViewwidget on the Dart side. - Limitation:
ShaderMaskandColorFilteredwidgets 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:
flutter build web --wasm. - Server Configuration: To enable multi-threading, configure your HTTP server to emit the following headers:
Cross-Origin-Embedder-Policy: credentialless(orrequire-corp)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
package:webanddart:js_interop. - Do NOT use:
dart:html,dart:js, orpackage:js. These are incompatible with Wasm compilation. - Embedding HTML: Use
HtmlElementView.fromTagNameto inject arbitrary HTML elements (like<video>) into the Flutter Web DOM.
Workflows
Workflow: Creating a Native FFI Integration
Use this workflow when binding to a C/C++ library.
- Task Progress:
- 1. Run
flutter create --template=package_ffi <name>. - 2. Place C/C++ source code in the
src/directory. - 3. Ensure all exported C++ functions are wrapped in
extern "C"and visibility attributes. - 4. Configure
ffigen.yamlto point to your header files. - 5. Run
dart run ffigento generate Dart bindings. - 6. Modify
hook/build.dartif linking against pre-compiled or system libraries. - 7. Run validator ->
flutter test-> review errors -> fix.
- 1. Run
Workflow: Implementing a Type-Safe Platform Channel (Pigeon)
Use this workflow when you need to call Kotlin/Swift APIs from Dart.
- Task Progress:
- 1. Add
pigeontodev_dependencies. - 2. Create
pigeons/messages.dartand define data classes and@HostApi()abstract classes. - 3. Run the Pigeon generator script to output Dart, Kotlin, and Swift files.
- 4. Android: Implement the generated interface in
MainActivity.ktor your Plugin class. - 5. iOS: Implement the generated protocol in
AppDelegate.swiftor your Plugin class. - 6. Dart: Import the generated Dart file and call the API methods.
- 7. Run validator -> verify cross-platform compilation -> review errors -> fix.
- 1. Add
Workflow: Embedding a Native Platform View
Use this workflow when embedding a native UI component (e.g., a native map or camera view).
- Task Progress:
- 1. Dart: Create a widget that conditionally returns
AndroidView(orPlatformViewLink) for Android, andUiKitViewfor iOS based ondefaultTargetPlatform. - 2. Android: Create a class implementing
PlatformViewthat returns the native AndroidView. - 3. Android: Create a
PlatformViewFactoryand register it inconfigureFlutterEngine. - 4. iOS: Create a class implementing
FlutterPlatformViewthat returns the nativeUIView. - 5. iOS: Create a
FlutterPlatformViewFactoryand register it inapplication:didFinishLaunchingWithOptions:. - 6. Run validator -> test on physical Android and iOS devices -> review UI clipping/scrolling issues -> fix.
- 1. Dart: Create a widget that conditionally returns