# Dart FFI (Foreign Function Interface)
Dart FFI permite llamar a librerías escritas en C, C++ o Rust directamente desde Dart, **sin usar Method Channels**. Es mucho más rápido (síncrono, sin serialización de mensajes) y es la forma preferida para operaciones computacionales intensivas o para reutilizar librerías de sistema existentes (como SQLite, OpenSSL, TensorFlow Lite).
## ¿Cómo funciona?
1. Cargas una librería dinámica (`.so` en Linux/Android, `.dylib` en macOS, `.dll` en Windows).
2. Buscas los símbolos (funciones) en esa librería.
3. Defines la firma de la función en Dart y en C.
4. Llamas a la función como si fuera Dart.
## Ejemplo Básico: Llamando a C
Supongamos que tienes una función en C:
```c
// hello.c
int sum(int a, int b) {
return a + b;
}
```
### 1. Definir las firmas (typedefs)
```dart
import 'dart:ffi' as ffi;
import 'dart:io' show Platform;
// Firma en C (tipos de FFI)
typedef SumFuncC = ffi.Int32 Function(ffi.Int32 a, ffi.Int32 b);
// Firma en Dart (tipos de Dart)
typedef SumFuncDart = int Function(int a, int b);
```
### 2. Cargar y Vincular
```dart
void main() {
// Cargar librería dinámica
var libraryPath = 'libhello.so';
if (Platform.isMacOS) libraryPath = 'libhello.dylib';
if (Platform.isWindows) libraryPath = 'hello.dll';
final dylib = ffi.DynamicLibrary.open(libraryPath);
// Buscar la función 'sum'
final SumFuncDart sum = dylib
.lookup>('sum')
.asFunction();
// Usar
print('3 + 5 = ${sum(3, 5)}');
}
```
## Trabajando con Memoria (Punteros)
FFI te da control manual sobre la memoria. Debes ser cuidadoso para evitar fugas o segfaults.
```dart
import 'dart:ffi';
import 'package:ffi/ffi.dart'; // Paquete útil para manejo de memoria
void main() {
// Asignar memoria en el heap nativo (malloc)
final Pointer p = calloc();
// Escribir valor
p.value = 42;
print(p.value);
// Liberar memoria (free)
calloc.free(p);
}
```
## Strings
Los Strings de Dart (UTF-16) y C (char*, UTF-8 terminados en null) son diferentes. `package:ffi` ayuda a convertir.
```dart
import 'package:ffi/ffi.dart';
void callCStringFunction(String dartString) {
// Convertir Dart String -> C String (char*)
final pointer = dartString.toNativeUtf8();
// Llamar función C
cFunction(pointer);
// Liberar memoria del string
calloc.free(pointer);
}
```
## FFIgen
Escribir los bindings manualmente para librerías grandes es tedioso. **ffigen** es una herramienta oficial que lee archivos de cabecera `.h` de C y genera automáticamente el código Dart FFI.
1. Configuras `pubspec.yaml` con los headers.
2. Ejecutas `dart run ffigen`.
3. Obtienes un archivo `.dart` con todas las clases y funciones listas para usar.
## FFI vs Method Channels
| Característica | Method Channels | Dart FFI |
|----------------|-----------------|----------|
| Lenguajes | Java, Kotlin, Obj-C, Swift | C, C++, Rust, Go (cgo) |
| Ejecución | Asíncrona (siempre) | Síncrona (por defecto) o Asíncrona |
| Rendimiento | Overhead por serialización | Muy rápido (llamada directa) |
| Uso principal | APIs de plataforma (Cámara, GPS) | Librerías de cómputo, Motores, DBs |
## Conclusión
Dart FFI es una herramienta de poder para:
- Integrar código de alto rendimiento (Rust/C++).
- Reutilizar ecosistemas existentes de C.
- Realizar operaciones síncronas bloqueantes (en un Isolate) sin el overhead de mensajes.
Este apartado profundiza en los conceptos clave, proporcionando ejemplos prácticos y mejores prácticas para su aplicación en proyectos reales.
Al comprender estos detalles, podrás diseñar soluciones más robustas, mantenibles y escalables en tus aplicaciones Flutter y Dart.