Cómo elegir los mejores paquetes para Flutter y crear tu primera app de escritorio multiplataforma

oct. 1, 2024

Este artículo forma parte de una serie:

Ya hemos hablado de Flutter y como ha ganado popularidad como uno de los frameworks más potentes para crear aplicaciones móviles con un solo código base. Sin embargo, sus capacidades van más allá del desarrollo de aplicaciones móviles y web, permitiendo la creación de aplicaciones de escritorio multiplataforma. Con Flutter, podemos desarrollar para Linux, Mac y Windows, utilizando las mismas herramientas y paradigmas que ya conocemos, sin necesidad de aprender tecnologías adicionales específicas para cada plataforma.

El desarrollo de aplicaciones de escritorio a menudo ha sido un desafío para los desarrolladores que quieren ofrecer una experiencia uniforme en múltiples sistemas operativos. Tradicionalmente, esto requería aprender varias herramientas y lenguajes de programación según la plataforma: C# para Windows, Objective-C o Swift para macOS, y lenguajes basados en Linux para otros entornos. Flutter elimina esta complejidad ofreciendo una única solución para todas estas plataformas, utilizando Dart como lenguaje central y brindando un rico ecosistema de widgets y herramientas.

El motor gráfico de Flutter, Skia, permite crear interfaces de usuario altamente personalizables y fluidas, sin importar la plataforma en la que se ejecute la aplicación. Esto asegura que nuestras aplicaciones mantengan la misma calidad visual y rendimiento en cualquier sistema operativo, ya sea en un dispositivo móvil o en un escritorio.

Otro aspecto fundamental es la capacidad de prototipado rápido. Al igual que en sus versiones móviles y web, Flutter en escritorio permite a los desarrolladores ver los cambios en tiempo real, gracias a la función Hot Reload. Esto facilita iteraciones rápidas y mejora la experiencia de desarrollo, sobre todo en las fases tempranas del ciclo de vida de la aplicación.

En este artículo, no sólo veremos cómo Flutter nos permite desarrollar aplicaciones de escritorio, sino que también exploraremos cómo elegir las bibliotecas adecuadas y qué consideraciones tomar al integrar funcionalidades específicas a través de paquetes externos. Después, pondremos todo esto en práctica con un ejemplo real con una aplicación para visualizar la evolución de los valores de algunas criptomonedas.

Pub Dev y Flutter

Al desarrollar aplicaciones con Flutter, una de las fuentes más importantes de recursos es Pub Dev, el repositorio oficial de paquetes para el ecosistema de Dart y Flutter. Aquí es donde encontraremos bibliotecas y herramientas adicionales que nos ayudarán a implementar funcionalidades en nuestras aplicaciones, desde gestión de estado hasta gráficos, bases de datos locales, y mucho más. Sin embargo, al trabajar con múltiples plataformas como móvil, web y escritorio, es crucial saber distinguir los detalles clave de cada biblioteca antes de integrarla en nuestro proyecto.

¿Qué tener en cuenta al elegir un paquete en Pub Dev?

Cuando navegamos por Pub Dev, hay varios factores a tener en cuenta para asegurarnos de que el paquete seleccionado es adecuado para nuestra aplicación y compatible con las plataformas objetivo.

1. Compatibilidad de la plataforma

Uno de los detalles más importantes al seleccionar un paquete es asegurarnos de que es compatible con las plataformas en las que queremos que se ejecute nuestra aplicación. Pub Dev ofrece un apartado específico en cada paquete, debajo del nombre del mismo, que indica claramente para qué entornos el paquete ha sido diseñado. Debemos prestar atención a que el paquete soporte:

  • Android y iOS para aplicaciones móviles.
  • Web para aplicaciones que se ejecutan en navegadores.
  • Linux, MacOS y Windows para aplicaciones de escritorio.

Esta información nos ahorra tiempo y nos evita errores al seleccionar una biblioteca que no funcione en todas las plataformas en las que planeamos desplegar nuestra aplicación.

2. Versión del paquete

Otro aspecto fundamental es la versión del paquete que estamos integrando. En Pub Dev, las versiones están claramente marcadas y debemos asegurarnos de que estamos utilizando la última versión estable. Las versiones suelen seguir el estándar de versionado semántico (x.y.z), donde:

  • x es la versión principal (major): indica cambios significativos o incompatibles con versiones anteriores.
  • y es la versión menor (minor): introduce nuevas características, pero sigue siendo compatible con versiones anteriores.
  • z son las correcciones de errores (patches).

Debemos tener cuidado con las versiones mayores, ya que pueden implicar cambios importantes en la API del paquete y pueden requerir modificaciones en nuestro código.

3. Soporte para la versión 3 de Flutter

La versión 3 de Flutter introduce mejoras significativas en el rendimiento y la estabilidad de las aplicaciones, así como nuevas características y optimizaciones. Al elegir un paquete, es importante asegurarnos de que sea compatible con la versión 3 de Dart, ya que esto garantiza que podremos aprovechar al máximo las ventajas de la última versión de Flutter. En Pub Dev, podemos ver si un paquete es compatible con la versión 3 de Dart justo al lado de su nombre.

4. Puntuaciones de salud y popularidad

Pub Dev también asigna puntuaciones a los paquetes basándose en varios factores, como la popularidad, la salud y el mantenimiento. Estas puntuaciones nos ayudan a identificar paquetes confiables y bien mantenidos por la comunidad. Un paquete con una alta puntuación de popularidad probablemente sea utilizado por muchos desarrolladores y cuente con una comunidad activa que reporta y soluciona problemas rápidamente.

Elegir paquetes con buenas puntuaciones y mantenimiento activo puede ahorrarnos muchos problemas en el futuro, ya que es más probable que sean actualizados regularmente y compatibles con futuras versiones de Flutter.

5. Documentación y Ejemplos

Finalmente, antes de elegir un paquete, es recomendable revisar la documentación y los ejemplos que proporciona. Una buena documentación es crucial para integrar un paquete de manera eficiente, y los ejemplos nos permiten ver rápidamente cómo implementar las funcionalidades que ofrece el paquete. Además, es útil verificar si el paquete tiene un repositorio en GitHub donde se pueden reportar errores o sugerir mejoras.

Para nuestro ejemplo vamos a utilizar los siguientes paquetes de Pub Dev:

  • fl_chart: Utilizado para mostrar gráficos interactivos.
  • http: Permite realizar solicitudes HTTP para obtener los datos desde una API externa en nuestro caso.
  • shared_preferences: Para almacenar datos localmente en la aplicación, como las preferencias de criptomonedas seleccionadas.
  • intl: Proporciona herramientas para el formateo de fechas y números en diferentes formatos internacionales.

Todos ellos compatibles con Flutter Desktop nos proporcionan las herramientas necesarias para crear una aplicación con los requisitos establecidos. En este ejemplo práctico crearemos un visualizador de la evolución del precio de algunas criptomonedas.

Ejemplo práctico: Evolución del precio de criptomonedas

Ahora que ya hemos explorado cómo identificar las bibliotecas más adecuadas para nuestro proyecto en Pub Dev, vamos a sumergirnos en nuestro ejemplo práctico, construiremos un visualizador de la evolución de valores de criptomonedas con una interfaz sencilla y clara. La aplicación permitirá al usuario seleccionar las criptomonedas que desea visualizar y mostrará un gráfico interactivo con los precios de las monedas digitales en un período de tiempo seleccionado, también modificable.

Funcionalidades del Proyecto

Antes de pasar al código fuente, veamos brevemente la interfaz del proyecto. Nuestra aplicación consistirá en:

  1. Gráfica de visualización de precios de las criptomonedas seleccionadas por el usuario.
  2. Selección de criptomonedas a través de un diálogo que permite elegir entre diferentes opciones predefinidas.
  3. Control de período de tiempo para visualizar los precios en un rango de días seleccionado por el usuario con opción para 1 semana, 15 días, 1 mes ó 3 meses.
  4. Interacción con una API externa para obtener los datos actualizados de las criptomonedas.

Código fuente

A continuación, repasamos algunas de las partes más importantes del código fuente que hemos utilizado para crear esta aplicación. Tienes todo el código disponible en nuestro repositorio de Github.

1. Gráfica de evolución interactiva

Una de las partes fundamentales de esta aplicación es la visualización de los datos obtenidos de la API. Para mostrar de manera gráfica los valores de las criptomonedas seleccionadas, utilizamos el paquete fl_chart. Éste nos permite crear gráficos interactivos y altamente personalizables.

  
  Widget _buildLineChart() {
    DateTime today = DateTime.now();
    int daysInPeriod = int.parse(_selectedPeriod);
    DateTime startDate = today.subtract(Duration(days: daysInPeriod));

    return LineChart(
      LineChartData(
        maxX: daysInPeriod.toDouble() - 1,
        borderData: FlBorderData(
          show: true,
          border: Border(
            left: BorderSide(color: Colors.black),
            bottom: BorderSide(color: Colors.black),
            top: BorderSide.none,
            right: BorderSide.none,
          ),
        ),
        titlesData: FlTitlesData(
          show: true,
          bottomTitles: AxisTitles(
            sideTitles: SideTitles(
              showTitles: true,
              reservedSize: 22,
              interval: 1,
              getTitlesWidget: (value, meta) {
                DateTime date = startDate.add(Duration(days: value.toInt()));
                return SideTitleWidget(
                  axisSide: meta.axisSide,
                  child: Text(
                    DateFormat('dd/MM').format(date),
                    style: TextStyle(fontSize: 10),
                  ),
                );
              },
            ),
          ),
          leftTitles: AxisTitles(
            sideTitles: SideTitles(
              reservedSize: 40,
              showTitles: true,
              getTitlesWidget: (value, meta) {
                return Text('\$${value.toInt()}',
                    style: TextStyle(fontSize: 10));
              },
            ),
          ),
        ),
        lineBarsData: _cryptoPrices.entries.map((entry) {
          return LineChartBarData(
            spots: entry.value.asMap().entries.map((e) {
              return FlSpot(e.key.toDouble(), e.value);
            }).toList(),
            isCurved: true,
            color: _cryptoList[entry.key],
            barWidth: 2,
            dotData: FlDotData(show: false),
          );
        }).toList(),
      ),
    );
  }
    

Aquí hemos creado un gráfico de líneas que muestra los valores de las criptomonedas en un período de tiempo seleccionado por el usuario. Utilizamos la clase LineChart de fl_chart para configurar los datos y la apariencia del gráfico, incluyendo los ejes, títulos y colores de las líneas.

2. Selección de Criptomonedas

Para permitir al usuario elegir las criptomonedas que desea visualizar, utilizamos un diálogo emergente que muestra una lista de opciones. Para implementar esta funcionalidad, creamos un diálogo personalizado con un Widget sin estado que utiliza un AlertDialog en el que se muestra una lista de opciones de criptomonedas predeterminadas. Si necesitas recordar cómo era exactamente el tema de los estados en Flutter, puedes echar un vistazo a nuestro artículo hablando sobre los Widgets, la piedra angular de Flutter.

  
  class SelectCryptoDialog extends StatelessWidget {
    final Map<String, Color> cryptoList;
    final Map<String, bool> selectedCryptos;
    final Function(String, bool) onSelected;
  
    const SelectCryptoDialog({
      required this.cryptoList,
      required this.selectedCryptos,
      required this.onSelected,
    });
  
    @override
    Widget build(BuildContext context) {
      return AlertDialog(
        title: Text('Select Cryptocurrencies'),
        content: SingleChildScrollView(
          child: StatefulBuilder( // Asegura que el estado se actualice correctamente dentro del diálogo
            builder: (BuildContext context, StateSetter setState) {
              return Column(
                mainAxisSize: MainAxisSize.min,
                children: cryptoList.keys.map((crypto) {
                  return CheckboxListTile(
                    title: Text(crypto),
                    value: selectedCryptos[crypto],
                    activeColor: cryptoList[crypto],
                    onChanged: (bool? selected) {
                      setState(() {
                        onSelected(crypto, selected!); // Actualizar selección
                      });
                    },
                  );
                }).toList(),
              );
            },
          ),
        ),
        actions: [
          TextButton(
            child: Text('Close'),
            onPressed: () {
              Navigator.of(context).pop();
            },
          ),
        ],
      );
    }
  }
    

En este fragmento de código, creamos un diálogo emergente que muestra una lista de opciones de criptomonedas. Utilizamos un AlertDialog para mostrar las opciones y permitir al usuario seleccionar o deseleccionar las criptomonedas deseadas. Estas criptomonedas son las que se mostrarán en el gráfico de evolución de precios y podrán ser mostrarse u ocultarse utilizando los controles de visibilidad.

3. Interacción con una API Externa

Para obtener los datos de las criptomonedas, utilizamos una API externa que proporciona información actualizada sobre los valores de las monedas digitales. En este caso, utilizamos la API de CoinGecko para obtener los precios de las criptomonedas seleccionadas.

  
  Future<List<double>> getCryptoPrices(String coinId, String days) async {
    try {
      final url = Uri.parse('$baseUrl/coins/$coinId/market_chart?vs_currency=usd&days=$days');
      final response = await http.get(url);

      if (response.statusCode == 200) {
        final data = json.decode(response.body);
        List<double> prices = List<double>.from(data['prices'].map((priceData) => priceData[1]));
        return prices;
      } else {
        throw Exception('Failed to load data: ${response.statusCode}');
      }
    } catch (e) {
      throw Exception('Error fetching data: $e');
    }
  }
  

En este fragmento de código, realizamos una solicitud HTTP a la API de CoinGecko para obtener los precios de la criptomoneda indicada. Con la biblioteca http realizamos la solicitud y jsonDecode se encarga de gestionar
la respuesta JSON. Una vez que obtenemos los datos, actualizamos el estado de la aplicación con los precios de las criptomonedas.

Compilar el código es tan sencillo como ejecutar flutter run -d windows para Windows, flutter run -d macos para Mac o flutter run -d linux para Linux. Flutter Desktop se encargará de compilar la aplicación para la plataforma indicada y generará el ejecutable para distribuir la aplicación.

Te invito a probarlo y a jugar con la aplicación, puedes encontrar el código fuente completo en nuestro repositorio de Github y seguir explorando las posibilidades de Flutter Desktop. Podrías añadir más funcionalidades como mostrar el precio actual de las criptomonedas, una gráfica que muestre los cambios por horas o periodos más cortos, o incluso implementar un sistema de notificaciones para cambios significativos en los precios. También podrías mejorar el diseño de la aplicación para hacerla más atractiva visualmente, ahora mismo utiliza la configuración por defecto de Flutter. Hay un montón de funcionalidades y mejoras para añadir a este proyecto.

Conclusión

En este artículo, hemos explorado cómo Flutter puede ser utilizado para crear aplicaciones de escritorio multiplataforma, junto con una guía sobre cómo elegir paquetes compatibles para tu proyecto. Hemos visto cómo identificar las bibliotecas más adecuadas en Pub Dev y hemos aplicado estos conocimientos en un ejemplo práctico de un visualizador de la evolución de criptomonedas.

Flutter Desktop ofrece una solución poderosa y unificada para el desarrollo de aplicaciones de escritorio, permitiéndonos crear experiencias de usuario consistentes en múltiples sistemas operativos. Con la creciente popularidad de Flutter y su rico ecosistema de paquetes, es el momento perfecto para explorar las posibilidades que ofrece esta tecnología para el desarrollo de aplicaciones multiplataforma modernas. ¡Happy Coding!

Artículos relacionados

Quizá te puedan interesar

September 15, 2023

Introducción a Flutter

Flutter es un framework de desarrollo de aplicaciones móviles creado por Google, utiliza el motor de …

leer más