Por Daniel Alvarez
A la hora de hacer aplicaciones multiplataforma, una de las opciones más populares actualmente es Flutter. Es un framework versátil, ya que no sólo se limita a aplicaciones móviles, sino también para escritorio y web.
Sin embargo, es posible que en algún momento necesitemos integrar en nuestro código librerías de terceros escritas en lenguajes como C/C++, o en su defecto, que compilen a módulos de C como Go o Rust.
En estos casos, se emplean mecanismos denominados “foreign function interface” (FFI), los cuales nos permiten cumplir las acciones mencionadas previamente.
En el caso de Flutter, existe un paquete de Dart llamado FFI, que proporciona una serie de utilidades para interactuar con código nativo. En este artículo veremos un ejemplo de cómo implementar una librería nativa de C, dentro de un proyecto de Dart.
Imaginemos que tenemos el siguiente código en C:
|
|
Para poder emplear esta función ‘multiply’ desde nuestro proyecto de Dart, debemos de compilar el fichero generando una biblioteca compartida:
|
|
Ahora nos dirigimos al proyecto de Dart/Flutter, e instalamos la dependencia de FFI:
|
|
|
|
A continuación, creamos un fichero e incluimos las dependencias necesarias para poder empezar a llamar a las funciones nativas:
|
|
Hemos hecho lo siguiente:
Con esto, podemos proseguir con el ejemplo y llamar a la función “multiply”, de nuestra librería en C:
|
|
En esta parte del código, después de haber cargado la biblioteca dinámica compartida (_dynamicLib), se procede a:
Definir la función multiplyFFI. Para conseguir esto, debemos indicar distintas cosas:
Declaración que deseamos que tenga nuestra función. En este caso recibe dos enteros (int, int), y devuelve otro (int):
|
|
Declaración que emplea nuestra función “multiply”, en nuestro fichero math_operations. Como en este caso queremos interactuar con el código de C, debemos de emplear los tipos de FFI. Teniendo esto en cuenta, se reciben dos enteros (Int32, Int32), y se devuelve otro (Int32):
|
|
Finalmente, nos debería de quedar como en el ejemplo que vimos previamente:
|
|
Ejecutar la función MultiplyFFI que hemos generado previamente. La cual llamará a la función multiply de nuestra biblioteca compartida:
|
|
Con esto, ya habríamos cumplido nuestro propósito. Sin embargo, aunque a primera vista parezca simple porque sólo hemos trabajado con un método, no ocurre lo mismo cuando queremos emplear un gran número de ellos.
Realizar este proceso repetidamente, nos llevaría una larga cantidad de tiempo, y en algunos casos sería hasta inviable. Es por ello, que para solventar este problema, podemos emplear otro paquete denominado FFIGen.
Con esta herramienta, todas las conversiones se pueden realizar de manera automática. Imaginemos que tenemos los siguientes ficheros en C:
|
|
|
|
En este caso contamos con dos operaciones “add” y “multiply”. Las definiciones de dichos métodos que queremos usar, se encuentran en math_operations.h. Es decir, este será nuestro punto de entrada, y así lo tenemos que indicar dentro del pubspec.yaml:
|
|
Si contáramos con varios puntos de entrada, se podrían incluir sin ningún problema. Además, la configuración de FFIGen no tiene por qué ir incluida en el pubspec.yaml, puede ir aparte.
Cabe recalcar que hemos modificado el código de C, por lo que debemos de volver a generar la biblioteca compartida. Cuando nuestro código va escalando de tamaño, es mejor emplear CMake para estas generaciones, en el proyecto de este artículo puedes encontrar un ejemplo de uso para este caso.
Ahora procedemos a instalar FFIGen. En primer lugar, necesitaremos instalar algunas dependencias en función del sistema operativo. Con esto realizado, escribimos lo siguiente en la terminal:
|
|
|
|
Ya con todo configurado, generamos las funciones que servirán de enlace con nuestro código de C:
|
|
|
|
La salida de esta ejecución nos generará un fichero con el nombre que hayamos especificado (generated_bindings.dart en mi caso). Este fichero debemos importarlo en nuestro código de Dart para poder emplearlo:
|
|
Cómo se puede apreciar, solo tenemos que hacer una llamada, para crearnos un objeto con todas las funciones necesarias:
|
|
Ya con esto, mediante _bindings, podemos acceder a las funciones que realizamos en C previamente:
|
|
Alternativamente, si solo hubiéramos empleado FFI, el código hubiera sido de la siguiente manera:
|
|
Se percibe claramente que la versión usando FFIGen, es más corta y sencilla de entender, que la versión empleando únicamente FFI. Además, en este caso estamos trabajando solo con datos sencillos, pero para datos más complejos, es preferible que las vinculaciones se realicen de manera automática.
Con esto, ya tienes todo lo necesario para poder emplear tu librería de C dentro de tus proyectos de Dart/Flutter. Próximamente realizaré otro artículo de cómo serían las interacciones con tipos más complejos (struct, punteros…).
¡Hasta la próxima!🫡
Referencias:
¿Quieres más? te invitamos a suscribirte a nuestro boletín para avisarte cada vez que recopilemos contenido de calidad que compartir.
Si disfrutas leyendo nuestro blog, ¿imaginas lo divertido que sería trabajar con nosotros? ¿te gustaría?
Pero espera 🖐 que tenemos un conflicto interno. A nosotros las newsletter nos parecen 💩👎👹 Por eso hemos creado la LEAN LISTA, la primera lista zen, disfrutona y que suena a rock y reggaeton del sector de la programación. Todos hemos recibido newsletters por encima de nuestras posibilidades 😅 por eso este es el compromiso de la Lean Lista