Interop nativo en Flutter sin platform channels: FFIgen, JNIgen y SPM en 2026
Durante años, comunicar Flutter con código nativo (Swift/Objective-C en iOS, Kotlin/Java en Android) significaba escribir platform channels: mensajería asíncrona, serialización manual de datos y boilerplate a ambos lados del puente. En 2026 hay una alternativa que cambia el modelo: llamar a APIs nativas directamente desde Dart mediante interop por FFI, con generación de bindings vía FFIgen (Objective-C/Swift) y JNIgen (Java/Kotlin). Es más rápido, síncrono y permite tree-shaking. Pero no sustituye a los platform channels en todos los casos.
Esta guía explica qué es, qué ventajas reales aporta y —sobre todo— cuándo seguir usando platform channels. Lo escribimos desde la experiencia de un equipo 100% senior in-house que lleva desde 2011 construyendo apps en Flutter.
El problema de los platform channels
Un platform channel funciona como un canal de mensajes asíncrono entre Dart y la plataforma. Para exponer una API nativa tienes que:
- Definir un nombre de canal y un codec.
- Serializar argumentos a tipos básicos en Dart.
- Recibir el mensaje en Swift/Kotlin, deserializar y mapear a la API nativa.
- Devolver el resultado por el mismo camino, de nuevo serializando.
Funciona, pero tiene costes: todo es asíncrono (aunque la operación nativa sea instantánea), hay overhead de serialización, el código no se beneficia del tree-shaking y mantienes boilerplate duplicado en cada plugin.
Qué cambia con FFIgen y JNIgen
La idea es bridgear Dart con el código nativo de cada plataforma directamente, sin pasar por la mensajería del canal:
- FFIgen genera bindings Dart que envuelven APIs de Objective-C y Swift.
- JNIgen hace lo propio con APIs de Java y Kotlin, apoyándose en la JNI.
Las ventajas frente a los platform channels:
| Aspecto | Platform channels | FFIgen / JNIgen |
|---|---|---|
| Modelo de llamada | siempre asíncrono | síncrono posible |
| Serialización de datos | manual, por mensaje | acceso directo a objetos nativos |
| Boilerplate | en Dart y nativo | bindings generados |
| Tree-shaking | no | sí (se elimina lo no usado) |
| Datos en la capa nativa | limitado | más estado puede vivir en lo nativo |
En la práctica, esto reduce drásticamente el código de pegamento que hay que escribir y mantener para crear y mantener plugins, y abre la puerta a usar prácticamente cualquier API de plataforma con menos fricción.
Ejemplo conceptual con JNIgen
Con JNIgen, una clase Kotlin se expone como una clase Dart generada que puedes invocar casi como código Dart normal:
// Binding generado a partir de una clase Kotlin
final scanner = DocumentScanner();
final result = scanner.scan(highRes: true); // llamada directa, sin canal
No hay nombre de canal, ni codec, ni handler asíncrono en MainActivity: el binding habla con la clase nativa por JNI.
Swift Package Manager: el otro cambio importante en iOS
En paralelo, Flutter ha hecho de Swift Package Manager (SPM) la vía de integración de dependencias iOS. Para los equipos esto significa:
- Integrar paquetes Swift directamente, sin la fricción histórica de configurar CocoaPods/Xcode a mano.
- Un modelo de dependencias más alineado con el ecosistema iOS moderno.
- Menos pasos de configuración manual al añadir SDKs nativos.
Combinado con FFIgen, el camino para envolver un SDK iOS y llamarlo desde Dart es notablemente más corto que con el modelo clásico de plugin + platform channel.
Cuándo NO usar interop directo (y seguir con platform channels)
Aquí está el matiz que rara vez se cuenta. El interop directo no es la respuesta para todo, y elegirlo a ciegas añade complejidad. Sigue prefiriendo platform channels —o un plugin establecido— cuando:
- Ya existe un plugin maduro y mantenido para lo que necesitas. No reinventes un binding si
url_launcher,camerao similar ya resuelve el caso. - Tu equipo no domina la plataforma nativa. El interop directo está pensado para desarrolladores con buen conocimiento de iOS/Android; sin él, depurar fallos de memoria o de JNI es más costoso que un canal asíncrono.
- La comunicación es naturalmente asíncrona y orientada a eventos (streams de sensores, callbacks del sistema): los platform channels y los
EventChannelsiguen encajando bien. - Necesitas máxima portabilidad y estabilidad a largo plazo: parte del tooling de interop sigue evolucionando, y las APIs generadas pueden cambiar entre versiones.
- El ahorro no compensa el riesgo: si llamas a una API nativa una vez al arrancar, el overhead asíncrono del canal es irrelevante.
Nuestra regla práctica: usa interop directo cuando el cuello de botella sea real (muchas llamadas, necesidad de sincronía, o un SDK nativo grande sin plugin) y tu equipo tenga músculo nativo. En el resto, la sencillez del platform channel gana.
Cómo lo evaluamos en Dribba
Cuando un proyecto necesita capacidades nativas, nuestro criterio es:
- ¿Existe ya un plugin sólido? Si sí, se usa y se acabó.
- ¿El acceso nativo es intensivo o necesita sincronía? Si no, platform channel.
- ¿El SDK nativo es grande o sin envoltorio? Candidato a FFIgen/JNIgen.
- ¿El equipo conoce la plataforma? Requisito para asumir interop directo con garantías.
- Medir: comparamos overhead real antes de comprometer una arquitectura.
Es la misma mentalidad de arquitectura limpia y de testing serio en Flutter con la que abordamos cualquier decisión técnica: la herramienta se elige por el problema, no por la novedad. Y se apoya en un pipeline de CI/CD que valida estos bindings en cada cambio.
Conclusión
El interop nativo directo —FFIgen para Objective-C/Swift, JNIgen para Java/Kotlin— y la adopción de SPM acercan a Flutter a las APIs de plataforma con menos boilerplate, llamadas síncronas y tree-shaking. Es una de las evoluciones más relevantes del framework en 2026 para equipos que tocan mucho código nativo. Pero los platform channels no han muerto: siguen siendo la opción correcta para casos asíncronos, plugins existentes y equipos sin profundidad nativa. La madurez del tooling todavía avanza, así que conviene adoptarlo donde aporta y no como reflejo.
¿Tu app necesita integrar SDKs nativos, sensores o capacidades de plataforma sin sacrificar mantenibilidad? En Dribba, Flutter Partner oficial de Google desde 2017, ayudamos a equipos a tomar estas decisiones de arquitectura con criterio. Cuéntanos tu caso.




