Pentru decenii întregi, apelarea codului nativ de sistem (C, C++, Rust, Go) din mediile de nivel înalt a necesitat punți de comunicare lente bazate pe canale de platformă (cum sunt Platform Channels din Flutter) sau pe mașina Java Native Interface (JNI). Aceste mecanisme impuneau serializarea și copierea fiecărui bloc de memorie între limbaje.
Dart FFI (Foreign Function Interface) elimină complet această barieră: biblioteca standard dart:ffi permite codului Dart să aloce memorie fizică nativă pe heap, să inspecteze pointeri și să apeleze direct funcții din biblioteci partajate (.so pe Linux/Android, .dylib pe macOS/iOS, .dll pe Windows) la viteza nativă a instrucțiunilor mașină!
# Execuție Dart FFI:
# [Cod Dart]
# │
# ▼ (Mapare de tipuri: Int32 -> int, Pointer)
# [dart:ffi Binding]
# │
# ▼ (Apel direct de adresă în spațiul de proces - Zero-Copy!)
# [Bibliotecă Nativă C / C++ / Rust (libnative.so)]
# │
# ▼ (Execuție directă pe hardware, fără punte sau serializare JSON!)
Maparea Tipurilor Primitive între C și Dart
Tip Nativ C (dart:ffi) |
Tip Corespondent în Dart | Dimensiune Memorie |
|---|---|---|
Int32 / Uint32 |
int |
4 octeți (32 biți) |
Int64 / Uint64 |
int |
8 octeți (64 biți) |
Double / Float |
double |
8 / 4 octeți |
Pointer<T> |
Pointer<T> |
8 octeți pe arhitecturi de 64 biți |
Struct |
Subclasă a Struct |
Structură binară compactă aliniată nativ în C |
import 'dart:ffi' as ffi;
import 'dart:io' show Platform;
import 'package:ffi/ffi.dart';
// Semnătura funcției native în C:
// int32_t add_numbers(int32_t a, int32_t b);
typedef NativeAddFunc = ffi.Int32 Function(ffi.Int32, ffi.Int32);
// Semnătura corespondentă în Dart:
typedef DartAddFunc = int Function(int, int);
void main() {
// 1. Încărcarea bibliotecii dinamice în funcție de sistemul de operare:
final libraryPath = Platform.isMacOS
? 'libmath_native.dylib'
: (Platform.isWindows ? 'math_native.dll' : 'libmath_native.so');
final dylib = ffi.DynamicLibrary.open(libraryPath);
// 2. Căutarea funcției prin adresa simbolică:
final DartAddFunc addNumbers = dylib
.lookup>('add_numbers')
.asFunction();
// 3. Execuție directă nativă:
final sum = addNumbers(15, 27);
print('Rezultat obținut direct din C nativ: $sum');
// 4. Alocare manuală de memorie nativă (Zero-Copy String):
final ffi.Pointer nativeString = 'Text alocat în heap-ul C'.toNativeUtf8();
try {
print('Lungime octeți: ${nativeString.length}');
} finally {
// Memoria alocată nativ trebuie eliberată manual pentru a evita memory leaks!
calloc.free(nativeString);
}
}