Módulo 04: Ecosistema Flutter Profesional

Ffi

Integracion Nativa

# 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.