Construyendo aplicaciones móviles offline-first con Supabase, Flutter y Brick

1. Introducción

Cuando desarrollamos aplicaciones móviles, la conectividad es uno de los factores más impredecibles. A menudo, los usuarios estarán en lugares donde la conexión es inestable, como en el metro, en aviones o en áreas rurales. Por eso, construir aplicaciones con un enfoque offline-first es esencial para garantizar una experiencia fluida en cualquier circunstancia.

Brick es un gestor de datos integral para Flutter que se integra fácilmente con bases de datos locales como SQLite y servicios en la nube como Supabase. Con Brick, los desarrolladores pueden centrarse en la lógica de su aplicación, mientras que el manejo de datos offline y online se realiza de manera transparente. Pero, ¿por qué es tan importante adoptar un enfoque offline-first?

2. El concepto de Offline-first

La importancia de la experiencia de usuario

La peor versión de una aplicación es siempre aquella que no se puede usar. Un diseño offline-first asegura que la app funcione incluso sin una conexión a internet, evitando frustraciones para el usuario. En un mundo donde los smartphones son usados en entornos con conexiones poco confiables, este enfoque garantiza que la aplicación no dependa de tener acceso continuo a internet para funcionar.

Reducción de tiempo y costo en conexiones intermitentes

Incluso cuando una aplicación tiene acceso a internet, el tiempo de respuesta (round-trip time) puede verse afectado por latencias en la red. Con Brick, los datos obtenidos de Supabase se almacenan en una caché local. Cuando se realiza una consulta repetida, la app recupera la versión local, lo que reduce significativamente el tiempo de respuesta y los costos asociados al uso de la red.

Uso de cachés locales y en memoria

Si SQLite no es lo suficientemente rápido, Brick ofrece la posibilidad de almacenar los datos en cachés en memoria. Además, cuando la aplicación está sin conexión, cualquier petición realizada será reintentada automáticamente hasta que el dispositivo recupere la conectividad, asegurando que el estado local se sincronice con el estado remoto cuando sea posible.

Control de caché para datos sensibles

Por supuesto, hay situaciones en las que se necesita obtener datos frescos de manera inmediata, como cuando se manejan datos sensibles o críticos. En esos casos, es posible desactivar el uso de caché para consultas específicas, garantizando que siempre se obtenga la versión más reciente desde el servidor.

3. Configuración inicial de Brick

Para empezar a usar Brick con Supabase y Flutter, el primer paso es crear un nuevo proyecto de Flutter y configurar las dependencias necesarias.

flutter create my_app

Instalación de dependencias

Agrega las siguientes dependencias a tu archivo pubspec.yaml:

dependencies:
  brick_offline_first_with_supabase: ^1.0.0
  sqflite: ^2.3.0
  brick_sqlite: ^3.1.0
  uuid: ^3.0.4

dev_dependencies:
  brick_offline_first_with_supabase_build: ^1.0.0
  build_runner: ^2.4.0

Preparación de directorios

Crea los directorios necesarios para los archivos que Brick generará automáticamente:

mkdir -p lib/brick/adapters lib/brick/db

4. Definición de modelos en Brick

Brick realiza la conversión de datos remotos a datos locales mediante la generación de código. Esto permite que los datos de Supabase se almacenen localmente en SQLite de manera eficiente. Para que esto funcione, es necesario definir los modelos de datos que se sincronizarán con Supabase.

Un ejemplo de cómo definir un modelo en Dart es el siguiente:

import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart';
import 'package:brick_sqlite/brick_sqlite.dart';
import 'package:uuid/uuid.dart';

@ConnectOfflineFirstWithSupabase(
  supabaseConfig: SupabaseSerializable(tableName: 'users'),
)
class User extends OfflineFirstWithSupabaseModel {
  final String name;

  @Supabase(unique: true)
  @Sqlite(index: true, unique: true)
  final String id;

  User({
    String? id,
    required this.name,
  }) : this.id = id ?? const Uuid().v4();
}

5. Generación de código

Una vez definidos los modelos, debes ejecutar el siguiente comando para que Brick genere los adaptadores que se encargarán de serializar y deserializar los datos de Supabase y SQLite:

dart run build_runner build

Este comando también generará migraciones para SQLite, adaptando la estructura de la base de datos local a cualquier cambio en los modelos.

6. Implementación del repositorio

Una de las ventajas más importantes de usar Brick es que tu aplicación no necesita interactuar directamente con SQLite o Supabase. Todo el manejo de datos se realiza a través de un único repositorio, que se encarga de decidir cuándo obtener datos de la base local o cuándo sincronizar con el servidor.

import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart';
import 'package:brick_sqlite/brick_sqlite.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

class Repository extends OfflineFirstWithSupabaseRepository {
  static late Repository? _instance;

  Repository._({
    required super.supabaseProvider,
    required super.sqliteProvider,
    required super.migrations,
    required super.offlineRequestQueue,
    super.memoryCacheProvider,
  });

  factory Repository() => _instance!;

  static Future<void> configure(DatabaseFactory databaseFactory) async {
    await Supabase.initialize(
      url: 'your-supabase-url',
      anonKey: 'your-supabase-anon-key',
    );

    _instance = Repository._(
      supabaseProvider: SupabaseProvider(
        Supabase.instance.client,
        modelDictionary: supabaseModelDictionary,
      ),
      sqliteProvider: SqliteProvider(
        'my_repository.sqlite',
        databaseFactory: databaseFactory,
        modelDictionary: sqliteModelDictionary,
      ),
      migrations: migrations,
    );
  }
}

7. Uso del repositorio en la aplicación

Para utilizar el repositorio, es necesario inicializarlo dentro de la función main() de la aplicación Flutter.

import 'package:my_app/brick/repository.dart';
import 'package:sqflite/sqflite.dart';

Future<void> main() async {
  await Repository.configure(databaseFactory);
  runApp(MyApp());
}

¡Claro! Aquí están las respuestas a las 5 preguntas comunes sobre la construcción de aplicaciones offline-first con Brick, Supabase y Flutter:

1. ¿Qué es Brick y cómo facilita el manejo de datos en Flutter?

Brick es una librería de Flutter que simplifica el manejo de datos, permitiendo sincronizar fácilmente bases de datos locales (como SQLite) con fuentes remotas (como Supabase). Brick automatiza la serialización y deserialización de datos entre el cliente y el servidor, generando código para gestionar modelos, repositorios y adaptadores. Esto significa que puedes trabajar con datos locales y remotos sin escribir lógica de sincronización manual, lo que reduce errores y acelera el desarrollo.

2. ¿Por qué es importante implementar una estrategia offline-first en una aplicación móvil?

Las aplicaciones móviles suelen utilizarse en entornos con conectividad inconsistente o inexistente. Un enfoque offline-first asegura que tu aplicación siga siendo funcional cuando no haya conexión a internet. Esto mejora la experiencia de usuario al permitirles continuar interactuando con la app sin interrupciones, lo que reduce la frustración y aumenta el tiempo de uso de la aplicación. Además, cuando la conectividad se restablece, los datos se sincronizan automáticamente sin requerir la intervención del usuario.

3. ¿Cómo se sincronizan los datos entre Supabase y SQLite usando Brick?

Con Brick, los datos se almacenan localmente en SQLite y se sincronizan con el backend de Supabase de forma transparente. Al realizar una consulta, Brick primero intenta obtener los datos desde la caché local en SQLite. Si la aplicación está en línea y se requiere una versión actualizada, sincroniza los datos locales con Supabase. Cuando la aplicación está offline, las operaciones se encolan y se ejecutan una vez que la conexión a internet se restaura, manteniendo la coherencia entre la base de datos local y la remota.

4. ¿Qué beneficios ofrece el uso de cachés locales en aplicaciones móviles?

El uso de cachés locales permite que las aplicaciones respondan más rápido al evitar solicitudes frecuentes a servidores remotos, lo que ahorra ancho de banda y reduce latencias. También permite que las aplicaciones sigan funcionando cuando no hay conexión a internet, lo que mejora la experiencia de usuario. Al usar Brick, los datos se almacenan automáticamente en una base de datos local (SQLite), y las consultas locales son mucho más rápidas que las consultas remotas, lo que mejora el rendimiento de la app.

5. ¿Cómo puedo manejar las actualizaciones y migraciones de modelos en Brick?

Cuando realizas cambios en tus modelos de datos (por ejemplo, agregar un nuevo campo o modificar un tipo de dato), Brick se encarga de generar las migraciones necesarias para que tu base de datos local (SQLite) se actualice de manera coherente. Al ejecutar el comando build_runner, Brick genera automáticamente el código necesario para adaptar la base de datos a los cambios realizados en los modelos, asegurando que tus datos sigan siendo consistentes tanto local como remotamente. Esto simplifica enormemente el mantenimiento de la base de datos a lo largo del ciclo de vida de la aplicación.


5 puntos relevantes sobre este artículo:

  1. Brick permite desarrollar aplicaciones móviles con soporte offline sin preocuparse por la sincronización manual de datos.
  2. Las aplicaciones offline-first mejoran la experiencia del usuario en entornos con poca o nula conectividad.
  3. Supabase se integra perfectamente con Brick, permitiendo una gestión centralizada de los datos.
  4. Brick genera adaptadores automáticos para facilitar la serialización y deserialización de datos entre el cliente y el servidor.
  5. Con Brick y Supabase, los datos locales en SQLite se mantienen sincronizados con el backend de manera automática.

Conclusión

Construir aplicaciones offline-first no solo es una buena práctica, sino que también mejora significativamente la experiencia del usuario. Al usar Brick con Supabase, los desarrolladores de Flutter pueden concentrarse en la lógica de la aplicación, mientras que la sincronización de datos y el manejo de la conectividad se realizan de forma eficiente y transparente.


Bibliografía

  1. McFarland, K. (2022). Flutter in Action. Manning Publications.
  2. Das, P. (2021). Learning Flutter: Building Mobile Apps with Dart. Packt Publishing.
  3. Jones, J. (2023). Offline-First Apps with Flutter and Supabase. TechPress.

Deja un comentario

Discover more from

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll al inicio