FFI
41.1 Calling C with dart:ffi
Structs (final class Point extends Struct { @Double() external double x; }), arrays, callbacks (Pointer.fromFunction, NativeCallable.listener for async callbacks from other threads), Finalizable/NativeFinalizer for cleanup, and Arena for scoped allocation.
ffigen generates bindings from C headers. jnigen generates Java/Kotlin bindings (Android). objective_c/ffigen handles Objective-C/Swift.
Native assets / build hooks (hook/build.dart) compile and bundle native code automatically with dart run/flutter run. This feature became stable around Dart 3.9/3.10, so check the docs for your version.
// native/add.c → gcc -shared -fPIC -o libadd.so add.c
int add(int a, int b) { return a + b; }
void greet(const char* name) { printf("Hello, %s\n", name); }import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
typedef AddNative = Int32 Function(Int32 a, Int32 b);
typedef AddDart = int Function(int a, int b);
typedef GreetNative = Void Function(Pointer<Utf8> name);
typedef GreetDart = void Function(Pointer<Utf8> name);
void main() {
final lib = DynamicLibrary.open(Platform.isWindows ? 'add.dll' : Platform.isMacOS ? 'libadd.dylib' : 'libadd.so');
final add = lib.lookupFunction<AddNative, AddDart>('add');
print(add(2, 3));
final greet = lib.lookupFunction<GreetNative, GreetDart>('greet');
final name = 'Dart'.toNativeUtf8(); // allocate C memory
greet(name);
malloc.free(name); // free it
}
// Modern annotation style (with @Native and native assets)
@Native<Int32 Function(Int32, Int32)>(symbol: 'add')
external int addNative(int a, int b);