Master Dart FFI: Step‑by‑Step Guide to Call C/C++ from Flutter and Back
This tutorial walks you through using Dart's foreign function interface (FFI) in Flutter, showing how to create a macOS plugin project, generate bindings with ffigen, call native C/C++ functions, handle callbacks and asynchronous threads, and integrate message passing between Dart isolates and native code.
What is FFI
FFI (Foreign Function Interface) is a mechanism that lets code written in one programming language call functions or services written in another language, similar to Java JNI.
Create a sample project
Generate a Flutter plugin project for macOS using the plugin_ffi template and run it to produce a macOS executable.
flutter --version flutter create --template=plugin_ffi --platforms=macos plugin_ffi_sample cd plugin_ffi_sample/example
flutter runInspect the plugin project
The example directory demonstrates how to use the plugin. The pubspec.yaml declares a path dependency on the plugin itself.
dependencies:
flutter:
sdk: flutter
plugin_ffi_sample:
path: ../Calling native functions from Dart
Import the generated bindings and call sum and sumAsync from Dart.
import 'package:plugin_ffi_sample/plugin_ffi_sample.dart' as plugin_ffi_sample;
class _MyAppState extends State<MyApp> {
late int sumResult;
late Future<int> sumAsyncResult;
@override
void initState() {
super.initState();
sumResult = plugin_ffi_sample.sum(1, 2);
sumAsyncResult = plugin_ffi_sample.sumAsync(3, 4);
}
}Generated binding file
The file plugin_ffi_sample_bindings_generated.dart is auto‑generated by ffigen and maps Dart calls to the native symbols.
// AUTO GENERATED FILE, DO NOT EDIT.
import 'dart:ffi' as ffi;
class PluginFfiSampleBindings {
final ffi.Pointer<ffi.NativeFunction<ffi.Int32 Function(ffi.Int32, ffi.Int32)>> _sum;
PluginFfiSampleBindings(ffi.DynamicLibrary dylib)
: _sum = dylib.lookup<ffi.NativeFunction<ffi.Int32 Function(ffi.Int32, ffi.Int32)>>('sum');
int sum(int a, int b) => _sum.asFunction<int Function(int, int)>()(a, b);
}Adding a C/C++ callback
Define a function pointer type pong and a ping function that invokes the callback.
typedef void (*pong)(void);
FFI_PLUGIN_EXPORT void ping(pong callback) {
printf("ping
");
callback();
}Regenerate bindings after changing the header.
flutter pub run ffigen --config ffigen.yamlAsynchronous thread callbacks
When using a C++ thread, wrap the callback with Dart_PostCObject_DL to send a message to a Dart SendPort instead of calling Dart code directly.
void entry_point(Dart_Port_DL port) {
printf("entry_point
");
Dart_CObject obj;
obj.type = Dart_CObject_kString;
obj.value.as_string = "pong";
Dart_PostCObject_DL(port, &obj);
}
FFI_PLUGIN_EXPORT void ping(Dart_Port_DL port) {
printf("ping
");
std::thread* t = new std::thread(entry_point, port);
}Integrating with Flutter
In Dart, create a ReceivePort to listen for messages from native code and pass its nativePort to ping. Also initialize the dynamically linked Dart API.
void initializeApiDL() => _bindings.ffi_Dart_InitializeApiDL(NativeApi.initializeApiDLData);
void ping() {
final receivePort = ReceivePort()..listen((msg) => print('pong $msg'));
_bindings.ping(receivePort.sendPort.nativePort);
}
@override
void initState() {
super.initState();
initializeApiDL();
ping();
sumResult = plugin_ffi_sample.sum(1, 2);
sumAsyncResult = plugin_ffi_sample.sumAsync(3, 4);
}Key take‑aways
Use toNativeUtf8 with an allocator and free the memory after the call. NativeFinalizer can bind Dart objects to C++ objects and run cleanup code when the Dart object is garbage‑collected.
By following these steps you can successfully call C/C++ code from Dart, handle synchronous and asynchronous callbacks, and communicate between native threads and Dart isolates.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
