Binding to native macOS code using dart:ffi
Flutter mobile and desktop apps can use the dart:ffi library to call native C APIs. FFI stands for foreign function interface. Other terms for similar functionality include native interface and language bindings.
Before your library or program can use the FFI library to bind to native code, you must ensure that the native code is loaded and its symbols are visible to Dart. This page focuses on compiling, packaging, and loading macOS native code within a Flutter plugin or app.
This tutorial demonstrates how to bundle C/C++ sources in a Flutter plugin and bind to them using the Dart FFI library on macOS. In this walkthrough, you'll create a C function that implements 32-bit addition and then exposes it through a Dart plugin named "native_add".
Dynamic vs static linking
#A native library can be linked into an app either dynamically or statically. A statically linked library is embedded into the app's executable image, and is loaded when the app starts.
                  Symbols from a statically linked library can be
                  loaded using DynamicLibrary.executable or
                  DynamicLibrary.process.
                
                  A dynamically linked library, by contrast, is distributed
                  in a separate file or folder within the app,
                  and loaded on-demand. On macOS, the dynamically linked
                  library is distributed as a .framework folder.
                
                  A dynamically linked library can be loaded into
                  Dart using DynamicLibrary.open.
                
API documentation is available from the Dart API reference documentation.
Create an FFI plugin
#If you already have a plugin, skip this step.
To create a plugin called "native_add", do the following:
$ flutter create --platforms=macos --template=plugin_ffi native_add
$ cd native_add
                  This will create a plugin with C/C++ sources in native_add/src.
                  These sources are built by the native build files in the various
                  os build folders.
                
                  The FFI library can only bind against C symbols,
                  so in C++ these symbols are marked extern "C".
                
                  You should also add attributes to indicate that the
                  symbols are referenced from Dart,
                  to prevent the linker from discarding the symbols
                  during link-time optimization.
                  __attribute__((visibility("default"))) __attribute__((used)).
                
On iOS, the native_add/macos/native_add.podspec links the code.
The native code is invoked from dart in lib/native_add_bindings_generated.dart.
The bindings are generated with package:ffigen.
Other use cases
#iOS and macOS
#
                  Dynamically linked libraries are automatically loaded by
                  the dynamic linker when the app starts. Their constituent
                  symbols can be resolved using DynamicLibrary.process.
                  You can also get a handle to the library with
                  DynamicLibrary.open
                   to restrict the scope of
                  symbol resolution, but it's unclear how Apple's
                  review process handles this.
                
                  Symbols statically linked into the application binary
                  can be resolved using DynamicLibrary.executable
                   or
                  DynamicLibrary.process.
                
Platform library
#To link against a platform library, use the following instructions:
- In Xcode, open Runner.xcworkspace.
- Select the target platform.
- Click + in the Linked Frameworks and Libraries section.
- Select the system library to link against.
First-party library
#
                  A first-party native library can be included either
                  as source or as a (signed) .framework file.
                  It's probably possible to include statically linked
                  archives as well, but it requires testing.
                
Source code
#To link directly to source code, use the following instructions:
- In Xcode, open - Runner.xcworkspace.
- 
                    Add the C/C++/Objective-C/Swift source files to the Xcode project. 
- 
                    Add the following prefix to the exported symbol declarations to ensure they are visible to Dart: C/C++/Objective-C objcextern "C" /* <= C++ only */ __attribute__((visibility("default"))) __attribute__((used))Swift swift@_cdecl("myFunctionName")
Compiled (dynamic) library
#To link to a compiled dynamic library, use the following instructions:
- 
                    If a properly signed Frameworkfile is present, openRunner.xcworkspace.
- Add the framework file to the Embedded Binaries section.
- Also add it to the Linked Frameworks & Libraries section of the target in Xcode.
Compiled (dynamic) library (macOS)
#To add a closed source library to a Flutter macOS Desktop app, use the following instructions:
- Follow the instructions for Flutter desktop to create a Flutter desktop app.
- 
                    Open the yourapp/macos/Runner.xcworkspacein Xcode.- Drag your precompiled library (libyourlibrary.dylib) intoRunner/Frameworks.
- Click Runnerand go to theBuild Phasestab.- Drag libyourlibrary.dylibinto theCopy Bundle Resourceslist.
- Under Embed Libraries, checkCode Sign on Copy.
- Under Link Binary With Libraries, set status toOptional. (We use dynamic linking, no need to statically link.)
 
- Drag 
- Click Runnerand go to theGeneraltab.- Drag libyourlibrary.dylibinto the Frameworks, Libraries and Embedded Content list.
- Select Embed & Sign.
 
- Drag 
- Click Runner and go to the Build Settings tab.- In the Search Paths section configure the
                            Library Search Paths to include the path
                            where libyourlibrary.dylibis located.
 
- In the Search Paths section configure the
                            Library Search Paths to include the path
                            where 
 
- Drag your precompiled library (
- 
                    Edit lib/main.dart.- Use DynamicLibrary.open('libyourlibrary.dylib')to dynamically link to the symbols.
- Call your native function somewhere in a widget.
 
- Use 
- Run flutter runand check that your native function gets called.
- 
                    Run flutter build macosto build a self-contained release version of your app.
Other Resources
#To learn more about C interoperability, check out these videos:
Unless stated otherwise, the documentation on this site reflects Flutter 3.35.5. Page last updated on 2025-10-28. View source or report an issue.