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.
info Note
This page describes using the dart:ffi
library in macOS desktop apps. For information on Android, see Binding to native Android code using dart:ffi. For information on iOS, see Binding to native iOS code using dart:ffi. This feature is not yet supported for web plugins.
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.
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
info Note
You can exclude platforms from --platforms
that you don't want to build to. However, you need to include the platform of the device you are testing on.
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.
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
.
To link against a platform library, use the following instructions:
Runner.xcworkspace
.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.
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")
To link to a compiled dynamic library, use the following instructions:
Framework
file is present, open Runner.xcworkspace
.To add a closed source library to a Flutter macOS Desktop app, use the following instructions:
yourapp/macos/Runner.xcworkspace
in Xcode.
libyourlibrary.dylib
) into Runner/Frameworks
.Runner
and go to the Build Phases
tab.
libyourlibrary.dylib
into the Copy Bundle Resources
list.Embed Libraries
, check Code Sign on Copy
.Link Binary With Libraries
, set status to Optional
. (We use dynamic linking, no need to statically link.)Runner
and go to the General
tab.
libyourlibrary.dylib
into the Frameworks, Libraries and Embedded Content list.libyourlibrary.dylib
is located.lib/main.dart
.
DynamicLibrary.open('libyourlibrary.dylib')
to dynamically link to the symbols.flutter run
and check that your native function gets called.flutter build macos
to build a self-contained release version of your app.To learn more about C interoperability, check out these videos:
Was this page's content helpful?
Unless stated otherwise, the documentation on this site reflects the latest stable version of Flutter. Page last updated on 2024-11-19. View source or report an issue.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4