betuko_offline_sync 3.3.0 copy "betuko_offline_sync: ^3.3.0" to clipboard
betuko_offline_sync: ^3.3.0 copied to clipboard

Ultra-simple offline-first Flutter package. Just get(), save(), and syncAll(). Automatic local storage with Hive, manual sync when you want.

Changelog #

Todos los cambios notables de este proyecto serán documentados en este archivo.

El formato está basado en Keep a Changelog, y este proyecto adhiere a Semantic Versioning.

3.3.0 - 2025-01-27 #

Nuevas Características #

Control de Upload (POST) por Manager

Ahora puedes controlar qué managers hacen POST (subida) y cuáles solo hacen GET (descarga):

// Manager con POST habilitado (sube y descarga)
final asistencias = OnlineOfflineManager(
  boxName: 'asistencias',
  endpoint: 'processes/payroll/daily-capture',
  uploadEnabled: true, // ✅ Permite POST
);

// Manager solo lectura (solo descarga, no sube)
final catalogos = OnlineOfflineManager(
  boxName: 'catalogos',
  endpoint: 'catalogs/items',
  uploadEnabled: false, // ❌ Solo GET
);

Valor por defecto: uploadEnabled: false (solo GET por defecto)

Mejoras en Background Sync

  • Inicialización automática de ConnectivityService en background
  • Mejor manejo de errores: Los errores de POST ya no se silencian, se propagan correctamente
  • Logs mejorados: Uso de developer.log() para que aparezcan en logcat incluso con la app cerrada
  • Detección automática: Si el boxName contiene "asistencia" o "attendance", se habilita uploadEnabled: true automáticamente en background

Mejoras en Manejo de Errores

  • Los errores de POST ahora se propagan correctamente en lugar de silenciarse
  • Logs detallados para cada registro que se intenta enviar
  • Contadores de éxitos/fallos en sincronización
  • Mejor información de errores en los resultados

📚 Documentación #

  • Nuevo archivo WORKMANAGER_SETUP.md con guía completa de configuración
  • Documentación detallada de permisos Android requeridos
  • Guía de troubleshooting para problemas comunes
  • Ejemplos completos de uso

🔧 Cambios Técnicos #

  • OnlineOfflineManager ahora acepta parámetro uploadEnabled (default: false)
  • SyncService respeta uploadEnabled y omite upload si es false
  • BackgroundSyncService guarda y restaura uploadEnabled en SharedPreferences
  • Mejora en logs de ApiClient usando developer.log() para background

3.2.7 - 2025-11-28 #

🐛 Corrección de Bug Crítico #

Logs de Background Sync ahora visibles en Logcat

El problema era que cuando la app estaba completamente cerrada, los print() no aparecían en logcat. Ahora se usa developer.log() que siempre aparece.

GlobalConfig.initSync() en Background

Se corrigió el uso de GlobalConfig.init() (async) en el callback de background. Ahora usa initSync() que es síncrono y funciona correctamente en el isolate de WorkManager.

Más tiempo de inicialización

Se aumentó el tiempo de espera para inicialización de managers de 500ms a 1500ms para dar más tiempo en el isolate de background.

Logs detallados

Ahora se muestran logs paso a paso de todo el proceso de sincronización en background:

═══════════════════════════════════════════════════════════
🔄 [BackgroundSync] INICIANDO SINCRONIZACIÓN EN BACKGROUND
═══════════════════════════════════════════════════════════
📦 Inicializando Hive...
📖 Leyendo configuración de SharedPreferences...
📋 Managers registrados:
   • boxNames: [reportes, usuarios]
   • endpoints: [/api/reportes, /api/usuarios]
⚙️ Inicializando GlobalConfig...
🔨 Creando 2 managers temporales...
🔄 EJECUTANDO SINCRONIZACIÓN...
📊 RESULTADOS:
   ✓ reportes: ÉXITO
   ✓ usuarios: ÉXITO
═══════════════════════════════════════════════════════════
✅ SINCRONIZACIÓN COMPLETADA en 3s
═══════════════════════════════════════════════════════════

3.2.5 - 2025-11-28 #

Mejora de Resiliencia #

Reintentos Automáticos en Peticiones HTTP

Ahora las peticiones HTTP (get y post) incluyen una política de reintentos automática (Exponential Backoff) para manejar errores transitorios de red, como fallos de resolución DNS justo después de reconectar.

  • Reintentos: Hasta 3 veces
  • Delay: Creciente (2s, 4s, 6s)
  • Errores cubiertos: SocketException, TimeoutException, Failed host lookup

Esto soluciona el problema donde el dispositivo dice tener internet, pero el DNS tarda unos segundos en resolver la dirección de la API, causando que la sincronización falle prematuramente.


3.2.4 - 2025-11-28 #

🐛 Corrección de Bug #

Fallback Optimista en Verificación de Conexión

Si todos los pings HTTP fallan (por ejemplo, en redes corporativas restrictivas o emuladores con configuraciones DNS complejas) pero el sistema operativo reporta que hay una interfaz de red activa (WiFi/Datos), ahora se asume que hay conexión.

Esto evita falsos negativos donde la app tiene internet pero los endpoints de verificación (Google/Cloudflare) están bloqueados o fallan por timeouts.

Logs de Conectividad Mejorados

Ahora se muestra exactamente qué endpoint está fallando y por qué en la consola.

🔍 [Connectivity] Verificando conexión real...
   • Probando ping a: https://api.miapp.com
   ⚠️ Falló ping a https://api.miapp.com: SocketException...
   • Probando ping a: https://clients3.google.com/generate_204
   ✅ Respuesta recibida (Status: 204)

Ajustes

  • Timeout por defecto aumentado a 8 segundos
  • Delay de reconexión por defecto aumentado a 5 segundos

3.2.3 - 2025-11-28 #

🐛 Corrección de Bug Crítico #

ConnectivityService ahora es Singleton Global

El problema era que cada OnlineOfflineManager creaba su propia instancia de ConnectivityService, y el listener de reconexión solo se suscribía a uno de ellos. Si había problemas de timing, los eventos de reconexión se perdían.

Solución:

  • ConnectivityService ahora usa el patrón Singleton
  • Todos los managers comparten el mismo stream global de conectividad
  • Se eliminaron las condiciones de carrera
  • Logs detallados para debug

Nuevos Métodos Estáticos #

Método Descripción
ConnectivityService.initializeGlobal() Inicializa el servicio global
ConnectivityService.globalConnectivityStream Stream global de conectividad
ConnectivityService.globalIsOnline Estado global de conexión
ConnectivityService.forceCheck() Forzar verificación de conectividad
ConnectivityService.disposeGlobal() Liberar recursos globales

📝 Logs Mejorados #

Ahora se muestran logs detallados del flujo de conectividad:

🔌 [Connectivity] Inicializando servicio global...
✅ [Connectivity] Servicio global inicializado. Online: true
🔌 [AutoSync] Configurando listener de conectividad...
🔌 [AutoSync] Estado inicial: online
✅ [AutoSync] Listener de conectividad configurado
🔌 [AutoSync] Cambio detectado: online (anterior: offline)
🔄 Auto-sync: conexión detectada, esperando 3s para estabilizar...

3.2.2 - 2025-11-28 #

🐛 Corrección de Bug #

Verificación de conexión más robusta

  • Se agregaron múltiples endpoints de verificación para redes que bloquean Google/Cloudflare
  • Ahora usa la API del usuario como primer endpoint de verificación
  • Timeouts más largos para conexiones lentas

Endpoints de verificación (en orden):

  1. API del usuario (baseUrl configurado)
  2. Google connectivity check (gstatic)
  3. Google generate_204
  4. Apple captive portal
  5. Cloudflare 1.1.1.1
  6. Google DNS

3.2.1 - 2025-11-28 #

🐛 Corrección de Bug #

Sincronización más confiable al reconectar

Se corrigió un problema donde la sincronización al reconectar fallaba porque connectivity_plus detectaba la conexión antes de que estuviera realmente disponible.

Mejoras #

Verificación de conexión real

  • Nuevo método ConnectivityService.hasRealConnection() que hace un ping HTTP real para verificar conectividad
  • Se usa Google's generate_204 endpoint con fallback a Cloudflare

Delay configurable antes de sincronizar

  • Nuevo parámetro reconnectDelaySeconds en GlobalConfig.init() (default: 3 segundos)
  • Permite que la conexión se estabilice antes de intentar sincronizar

Verificación opcional de conexión real

  • Nuevo parámetro verifyRealConnection en GlobalConfig.init() (default: true)
  • Si la verificación falla, reintenta una vez más antes de cancelar

📖 Uso #

// Configuración por defecto (recomendada)
await GlobalConfig.init(
  baseUrl: 'https://api.com',
  token: 'tu-token',
);

// Personalizar el comportamiento de reconexión
await GlobalConfig.init(
  baseUrl: 'https://api.com',
  token: 'tu-token',
  reconnectDelaySeconds: 5,     // Esperar 5 segundos (default: 3)
  verifyRealConnection: true,   // Verificar conexión real (default: true)
);

📝 Logs mejorados #

Ahora se muestra información clara sobre el proceso de reconexión:

🔄 Auto-sync: conexión detectada, esperando 3s para estabilizar...
🔍 Verificando conexión real...
✅ Conexión real verificada
🔄 Auto-sync: conexión recuperada, sincronizando...

3.2.0 - 2025-11-28 #

Nueva Característica Principal #

🌙 Background Sync con WorkManager (Android)

Ahora puedes sincronizar datos incluso cuando la app está completamente cerrada usando WorkManager.

Características:
  • Sincronización Periódica: Cada 15 minutos (mínimo permitido por Android)
  • Sincronización al Reconectar: Se ejecuta automáticamente cuando hay conexión disponible
  • Persistencia de Configuración: La configuración se guarda en SharedPreferences para el background isolate
  • Fácil Integración: Solo requiere llamar a BackgroundSyncService.initialize()
Uso Básico:
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Configurar con background sync habilitado
  await GlobalConfig.init(
    baseUrl: 'https://api.com',
    token: 'tu-token',
    enableBackgroundSync: true,
  );
  
  // Inicializar WorkManager
  await BackgroundSyncService.initialize();
  
  // Crear y registrar managers
  final reportes = OnlineOfflineManager(
    boxName: 'reportes',
    endpoint: '/api/reportes',
  );
  await BackgroundSyncService.registerManager(reportes);
  
  // Iniciar sync periódico
  await BackgroundSyncService.startPeriodicSync();
  
  runApp(MyApp());
}

🆕 Nuevas Clases y Métodos #

BackgroundSyncService

Método Descripción
initialize() Inicializa WorkManager
registerManager(manager) Registra un manager para background sync
unregisterManager(boxName) Desregistra un manager
startPeriodicSync() Inicia sync cada 15 minutos
syncWhenConnected() Programa sync cuando haya internet
stopPeriodicSync() Detiene sync periódico
cancelAll() Cancela todas las tareas
clearConfig() Limpia configuración (para logout)

GlobalConfig Actualizado

  • init() ahora es async y acepta enableBackgroundSync
  • Nuevo método initSync() para inicialización síncrona
  • Nuevo método saveForBackgroundSync()
  • Nuevo método loadFromPrefs()
  • updateToken() ahora es async y actualiza SharedPreferences

📦 Nuevas Dependencias #

  • workmanager: ^0.9.0+3 - Para tareas en background
  • shared_preferences: ^2.2.2 - Para persistir configuración

📝 Configuración Android Requerida #

Agregar en android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

⚠️ Limitaciones #

  • Solo Android: iOS tiene restricciones más estrictas para background tasks
  • Intervalo mínimo: 15 minutos (limitación de Android WorkManager)
  • Batería: Android puede demorar la ejecución para optimizar batería

📚 Documentación #

  • README.md actualizado con sección completa de Background Sync
  • Ejemplos de configuración y uso
  • Notas sobre logout y limpieza

3.1.0 - 2025-11-26 #

Nuevas Características #

Sincronización Automática

  • Sincronización Periódica: Se ejecuta automáticamente cada 10 minutos cuando hay conexión a internet
  • Sincronización al Reconectar: Se ejecuta automáticamente cuando se detecta que la conexión a internet se ha restaurado (de offline a online)
  • Sin Configuración Necesaria: Funciona automáticamente una vez que se crea el primer OnlineOfflineManager
  • Intervalo Configurable: El intervalo de sincronización se puede ajustar en GlobalConfig.syncMinutes (por defecto 10 minutos)

Detalles Técnicos

  • Timer periódico que ejecuta syncAll() cada 10 minutos cuando hay internet
  • Listener de conectividad que detecta cambios de estado de red
  • Sincronización automática al detectar reconexión (transición de offline a online)
  • Limpieza automática de recursos cuando no hay managers activos

📝 Documentación #

  • Documentación actualizada en README.md y README_SUPER_SIMPLE.md con información sobre sincronización automática
  • Ejemplos de uso de la sincronización automática agregados

🔧 Cambios Internos #

  • GlobalConfig.syncMinutes cambiado de 5 a 10 minutos por defecto
  • Agregado sistema de auto-sync con timer y listener de conectividad en OnlineOfflineManager
  • Método disposeAutoSync() agregado para limpieza de recursos

3.0.0 - 2025-11-26 #

🚀 MAJOR RELEASE - API Simplificada #

Esta versión es una reescritura completa enfocada en simplicidad extrema.

⚠️ BREAKING CHANGES #

GlobalConfig Simplificado

// ANTES (muchos parámetros)
GlobalConfig.init(
  baseUrl: 'https://api.com',
  token: 'tu-token',
  syncMinutes: 5,
  useIncrementalSync: true,
  pageSize: 25,
  lastModifiedField: 'updated_at',
  syncOnReconnect: true,
  maxLocalRecords: 1000,
  maxDaysToKeep: 7,
  maxPagesPerSync: 10,
  syncTimeoutMinutes: 30,
);

// DESPUÉS (solo 2 parámetros)
GlobalConfig.init(
  baseUrl: 'https://api.com',
  token: 'tu-token',
);

API del Manager Simplificada

// ANTES
final datos = await manager.getAll();  // Sincronizaba automáticamente (lento)
await manager.sync();
await manager.forceSync();
await manager.syncNow();
await manager.getSync();
await manager.getLocal();

// DESPUÉS
final datos = await manager.get();     // Siempre local (instantáneo)
await OnlineOfflineManager.syncAll();  // Un solo método para sincronizar

Nueva API Super Simple #

Métodos de Instancia

Método Descripción
get() Todos los datos locales (instantáneo)
getSynced() Solo datos sincronizados
getPending() Solo datos pendientes
getFullData() Datos + contadores (FullSyncData)
getSyncInfo() Solo contadores (SyncInfo)
save(data) Guardar localmente
delete(id) Eliminar
clear() Limpiar datos
reset() Reset completo

Métodos Estáticos

Método Descripción
syncAll() Sincronizar TODOS los managers
getAllSyncInfo() Estado de todos los managers
resetAll() Reset global
debugInfo() Info de debug en consola
getAllBoxesInfo() Info de boxes Hive
getTotalRecordCount() Total de registros
getTotalPendingCount() Total de pendientes
deleteAllBoxes() Eliminar boxes del disco

Nuevas Características #

Ver Estado de Sincronización

// Obtener todo junto
final data = await manager.getFullData();
print('Total: ${data.total}');
print('Sincronizados: ${data.syncedCount}');
print('Pendientes: ${data.pendingCount}');

// Acceder a los datos
for (final item in data.synced) { ... }
for (final item in data.pending) { ... }

Debug Info

await OnlineOfflineManager.debugInfo();
// Imprime info detallada de todos los managers y boxes

Estado Global

final estados = await OnlineOfflineManager.getAllSyncInfo();
for (final entry in estados.entries) {
  print('${entry.key}: ${entry.value.synced}/${entry.value.total}');
}

🗑️ Eliminado #

  • SyncConfig - Ya no se necesita
  • getAll() - Reemplazado por get()
  • getSync() / getLocal() - Reemplazados por getSynced() / getPending()
  • sync(), forceSync(), syncNow() - Reemplazados por syncAll()
  • syncAllManagers() - Reemplazado por syncAll()
  • Sincronización automática en get() - Ahora es manual con syncAll()
  • Parámetros de configuración avanzados en GlobalConfig

📝 Filosofía de la Nueva Versión #

  1. get() siempre es instantáneo - Lee datos locales sin esperar
  2. El usuario decide cuándo sincronizar - Llamando a syncAll()
  3. Configuración mínima - Solo baseUrl y token
  4. Una forma de hacer las cosas - Sin métodos redundantes

2.2.0 - 2025-01-27 #

🚀 MAJOR UPDATE - Ultra-Smart Sync & Duplicate Prevention #

Esta versión introduce sincronización ultra-inteligente y prevención de duplicados para una experiencia de sincronización perfecta.

Nuevas Características Principales #

🧠 Sincronización Ultra-Inteligente

  • Verificación Previa: Hace una consulta pequeña para verificar si hay cambios
  • Comparación Local: Compara registros existentes con los del servidor
  • Procesamiento Selectivo: Solo procesa registros nuevos o modificados
  • Logs Detallados: Muestra estadísticas de registros procesados

🧹 Prevención y Limpieza de Duplicados

  • Detección Automática: Identifica registros duplicados basándose en ID
  • Limpieza Automática: Se ejecuta después de cada sincronización incremental
  • Limpieza Manual: Método cleanDuplicates() para limpieza manual
  • Logs Informativos: Muestra cuántos duplicados se encontraron y eliminaron

⚡ Optimizaciones de Rendimiento

  • Límites de Seguridad: Máximo 10 páginas por sincronización (configurable)
  • Detección de Páginas Vacías: Se detiene si encuentra 2 páginas consecutivas vacías
  • Timeout Inteligente: Usa descarga completa si han pasado más de 30 minutos
  • Configuraciones Avanzadas: maxPagesPerSync, syncTimeoutMinutes

🔧 Mejoras Técnicas #

Sincronización Manual vs Automática

  • Sincronización Automática: Verifica tiempo transcurrido antes de sincronizar
  • Sincronización Manual: Siempre sincroniza sin verificar tiempo
  • Métodos Separados: _downloadFromServer() vs _downloadFromServerManual()
  • Comportamiento Consistente: Todos los métodos manuales funcionan igual

Nuevas Configuraciones

GlobalConfig.init(
  baseUrl: 'https://tu-api.com',
  token: 'tu-token',
  syncMinutes: 15, // Sincronizar cada 15 minutos
  maxPagesPerSync: 5, // Máximo 5 páginas por sincronización
  syncTimeoutMinutes: 30, // Usar descarga completa si han pasado más de 30 minutos
  pageSize: 50, // Páginas más grandes para menos requests
);

📊 Nuevos Métodos #

cleanDuplicates() - Limpieza de Duplicados

// Limpiar duplicados manualmente
await manager.cleanDuplicates();

Configuraciones Recomendadas por Tipo de App

// 📱 Para aplicaciones móviles
GlobalConfig.init(
  syncMinutes: 15,
  maxPagesPerSync: 3,
  syncTimeoutMinutes: 30,
  pageSize: 50,
);

// 💻 Para aplicaciones web
GlobalConfig.init(
  syncMinutes: 5,
  maxPagesPerSync: 10,
  syncTimeoutMinutes: 15,
  pageSize: 25,
);

// 🏢 Para aplicaciones empresariales
GlobalConfig.init(
  syncMinutes: 30,
  maxPagesPerSync: 20,
  syncTimeoutMinutes: 60,
  pageSize: 100,
);

🎯 Casos de Uso Optimizados #

Sincronización Inteligente

  • Primera sincronización: Descarga completa (normal)
  • Sincronizaciones posteriores:
    • Verifica si hay cambios antes de descargar
    • Solo procesa registros nuevos o modificados
    • Muestra estadísticas detalladas
    • Es mucho más rápida y eficiente

Prevención de Duplicados

  • Limpieza automática: Los duplicados se eliminan automáticamente
  • Mejor detección: Los registros existentes se actualizan correctamente
  • UI limpia: No más registros multiplicados en la interfaz
  • Control manual: Puedes limpiar duplicados cuando necesites

🐛 Correcciones Importantes #

Sincronización Manual

  • Comportamiento Consistente: Todos los métodos manuales funcionan igual
  • Sin Verificaciones de Tiempo: La sincronización manual siempre sincroniza
  • Logs Claros: Sabes exactamente qué tipo de sincronización se está ejecutando
  • Comportamiento Esperado: La sincronización manual funciona como el usuario espera

Prevención de Duplicados

  • Limpieza Automática: Los duplicados se eliminan automáticamente
  • Mejor Mapeo: Mapeo correcto entre IDs y claves de almacenamiento
  • Actualización Correcta: Los registros existentes se actualizan usando la clave correcta
  • Prevención de Creación: Evita crear nuevos registros cuando ya existen

📈 Beneficios de Rendimiento #

Antes (v2.1.0)

🔄 Sincronización manual no sincronizaba
🔄 Registros se multiplicaban en la interfaz
🔄 Descargas masivas en cada reinicio

Después (v2.2.0)

🧠 Sincronización ultra-inteligente
🧹 Limpieza automática de duplicados
⚡ Sincronización manual siempre funciona
📊 Logs detallados con estadísticas

🔄 Migración desde v2.1.0 #

Sin Cambios Requeridos

// ✅ Tu código actual funciona sin cambios
final manager = OnlineOfflineManager(
  boxName: 'datos',
  endpoint: 'https://api.ejemplo.com/datos',
);

Optimización Opcional

// 🚀 NUEVO: Agregar configuraciones para mejor rendimiento
GlobalConfig.init(
  baseUrl: 'https://tu-api.com',
  token: 'tu-token',
  maxPagesPerSync: 5, // Evitar descargas masivas
  syncTimeoutMinutes: 30, // Usar descarga completa cuando sea necesario
);

// 🚀 NUEVO: Limpiar duplicados si es necesario
await manager.cleanDuplicates();

🎉 Ejemplos de Uso Optimizado #

Sistema de Reportes Optimizado

class ReportService {
  static final manager = OnlineOfflineManager(
    boxName: 'reports',
    endpoint: 'harvest-delivery',
  );
  
  // Obtener reportes con sincronización inteligente
  static Future<List<Report>> getReports() async {
    final data = await manager.getAll(); // Sincronización automática inteligente
    return data.map((item) => Report.fromJson(item)).toList();
  }
  
  // Sincronización manual cuando sea necesario
  static Future<void> refreshReports() async {
    await manager.sync(); // Siempre sincroniza
  }
  
  // Limpiar duplicados si es necesario
  static Future<void> cleanupDuplicates() async {
    await manager.cleanDuplicates();
  }
}

📚 Nueva Documentación #

Guías de Optimización

  • Configuración Optimizada: Guía para evitar descargas masivas
  • Manejo de Duplicados: Cómo prevenir y limpiar duplicados
  • Sincronización Manual vs Automática: Diferencias y cuándo usar cada una
  • Configuraciones Recomendadas: Por tipo de aplicación

🎯 Beneficios de la v2.2.0 #

Para Desarrolladores

  • Sincronización Inteligente: Evita descargas innecesarias
  • Prevención de Duplicados: No más registros multiplicados
  • Configuración Flexible: Adaptable a diferentes tipos de apps
  • Logs Detallados: Mejor debugging y monitoreo

Para Usuarios Finales

  • UI Más Limpia: No más registros duplicados
  • Sincronización Más Rápida: Solo descarga cuando es necesario
  • Mejor Experiencia: Sincronización manual funciona como esperado
  • Datos Consistentes: Prevención automática de duplicados

2.1.0 - 2025-01-27 #

🚀 MAJOR UPDATE - Smart Sync Optimization & Performance Boost #

Esta versión introduce sincronización inteligente optimizada y configuraciones de rendimiento para una experiencia de desarrollo aún mejor.

Nuevas Características Principales #

⚡ Sincronización Inteligente Optimizada

  • Cache Inteligente: Sistema de caché con timestamps para evitar sincronizaciones innecesarias
  • Configuraciones Predefinidas: SyncConfig.frequent, SyncConfig.occasional, SyncConfig.rare, SyncConfig.manual
  • Timer Automático: Sincronización automática basada en intervalos configurables
  • Rendimiento Mejorado: Hasta 20x más rápido para datos en caché

🎯 Nuevas Configuraciones de Sincronización

SyncConfig.frequent - Para datos que cambian frecuentemente
final manager = OnlineOfflineManager(
  boxName: 'messages',
  endpoint: 'https://api.ejemplo.com/messages',
  syncConfig: SyncConfig.frequent, // Sincroniza cada minuto
);
SyncConfig.occasional - Para datos que cambian ocasionalmente (RECOMENDADO)
final manager = OnlineOfflineManager(
  boxName: 'seasons',
  endpoint: 'https://api.ejemplo.com/seasons',
  syncConfig: SyncConfig.occasional, // Sincroniza cada 15 minutos
);
SyncConfig.rare - Para datos que cambian raramente
final manager = OnlineOfflineManager(
  boxName: 'config',
  endpoint: 'https://api.ejemplo.com/config',
  syncConfig: SyncConfig.rare, // Sincroniza cada hora
);
SyncConfig.manual - Para sincronización manual
final manager = OnlineOfflineManager(
  boxName: 'reports',
  endpoint: 'https://api.ejemplo.com/reports',
  syncConfig: SyncConfig.manual, // Solo sincroniza manualmente
);

🚀 Nuevos Métodos Optimizados

getAllFast() - Acceso rápido sin sincronización
// ⚡ RÁPIDO - Sin sincronización automática
final data = await manager.getAllFast();
getAllWithSync() - Sincronización inteligente
// ⚡ INTELIGENTE - Sincroniza solo si es necesario
final data = await manager.getAllWithSync();
forceSync() - Sincronización forzada
// 🔄 FORZADA - Siempre sincroniza
await manager.forceSync();

🔧 Mejoras Técnicas #

CacheManager Inteligente

  • Timestamps Persistentes: Caché que persiste entre sesiones usando Hive
  • Verificación Automática: Detecta automáticamente si necesita sincronizar
  • Configuración Flexible: Intervalos personalizables por tipo de datos

Timer de Sincronización Automática

  • Timer Inteligente: Se ejecuta automáticamente según la configuración
  • Solo con Conexión: Se activa únicamente cuando hay internet
  • Gestión de Recursos: Se cancela automáticamente al cerrar

Logs Optimizados

  • Solo Errores Críticos: Eliminados logs innecesarios para mejor rendimiento
  • Debugging Efectivo: Mantiene información esencial para errores
  • Código Más Limpio: Librería más profesional y silenciosa

📚 Nueva Documentación #

Guías de Optimización

  • OPTIMIZATION_GUIDE.md: Guía completa de optimización de rendimiento
  • CLEANUP_SUMMARY.md: Resumen de limpieza de logs
  • Ejemplos Prácticos: Casos de uso optimizados para diferentes tipos de datos

Mejores Prácticas

// 🎯 Para datos que cambian ocasionalmente (temporadas, categorías)
final seasonsManager = OnlineOfflineManager(
  boxName: 'seasons',
  endpoint: 'https://api.ejemplo.com/seasons',
  syncConfig: SyncConfig.occasional, // Sincroniza cada 15 minutos
);

// Uso normal - MUY RÁPIDO
final seasons = await seasonsManager.getAllFast();

// Solo cuando necesites datos frescos
if (needsFreshData(seasons)) {
  await seasonsManager.forceSync();
  final freshSeasons = await seasonsManager.getAllFast();
}

🎯 Casos de Uso Optimizados #

Datos Frecuentes (Mensajes, Notificaciones)

  • Configuración: SyncConfig.frequent
  • Método: getAllWithSync()
  • Resultado: Sincronización cada minuto automáticamente

Datos Ocasionales (Temporadas, Categorías)

  • Configuración: SyncConfig.occasional
  • Método: getAllFast() + forceSync() cuando sea necesario
  • Resultado: Hasta 20x más rápido, sincronización inteligente

Datos Raros (Configuración, Usuarios)

  • Configuración: SyncConfig.rare
  • Método: getAllFast() + sincronización manual
  • Resultado: Máximo rendimiento, control total

Datos Manuales (Reportes, Estadísticas)

  • Configuración: SyncConfig.manual
  • Método: getAllFast() + forceSync() solo cuando sea necesario
  • Resultado: Control completo sobre cuándo sincronizar

Beneficios de Rendimiento #

Antes (v2.0.0)

🔄 Sincronizando antes de obtener datos...
🔄 Iniciando sincronización automática...
📥 Descargando datos del servidor...
✅ Descargados 9 registros
✅ Sincronización completada

Tiempo: ~2-3 segundos por consulta

Después (v2.1.0)

⚡ Usando datos en caché (sincronización omitida)

Tiempo: ~50-100ms por consulta

🐛 Correcciones Importantes #

Sincronización Optimizada

  • Cache Inteligente: Evita sincronizaciones innecesarias
  • Timer Automático: Sincronización programada eficiente
  • Configuración Flexible: Diferentes estrategias por tipo de datos
  • Logs Limpios: Solo errores críticos, mejor rendimiento

Gestión de Recursos

  • Timer Management: Cancelación automática de timers
  • Memory Optimization: Mejor gestión de memoria
  • Error Handling: Manejo robusto de errores silencioso

🔄 Migración desde v2.0.0 #

Sin Cambios Requeridos

// ✅ Tu código actual funciona sin cambios
final manager = OnlineOfflineManager(
  boxName: 'seasons',
  endpoint: 'https://api.ejemplo.com/seasons',
  // syncConfig: SyncConfig.occasional, // NUEVO: Agregar para optimización
);

Optimización Opcional

// 🚀 NUEVO: Agregar configuración para mejor rendimiento
final manager = OnlineOfflineManager(
  boxName: 'seasons',
  endpoint: 'https://api.ejemplo.com/seasons',
  syncConfig: SyncConfig.occasional, // Agregar esta línea
);

// 🚀 NUEVO: Usar getAllFast() para mejor rendimiento
final data = await manager.getAllFast(); // En lugar de getAllWithSync()

📈 Métricas de Rendimiento #

Mejoras Cuantificables

  • Velocidad: Hasta 20x más rápido para datos en caché
  • Consumo de Datos: Reducido en 80% para datos ocasionales
  • Batería: Menor consumo por menos operaciones de red
  • UX: Carga instantánea de datos locales

Casos de Uso Reales

  • Temporadas: De 2-3 segundos a 50-100ms
  • Categorías: Sincronización solo cuando es necesario
  • Configuración: Carga instantánea, sincronización manual
  • Reportes: Control total sobre cuándo actualizar

🧪 Testing Actualizado #

Nuevos Tests

  • Cache Management: Tests para sistema de caché inteligente
  • Sync Configurations: Tests para todas las configuraciones
  • Timer Management: Tests para sincronización automática
  • Performance Tests: Tests de rendimiento y optimización

🎉 Ejemplos de Uso Optimizado #

Sistema de Temporadas Optimizado

class SeasonService {
  static final SeasonService _instance = SeasonService._internal();
  factory SeasonService() => _instance;
  SeasonService._internal();

  OnlineOfflineManager? _manager;
  bool _isInitialized = false;

  void initialize() {
    if (_isInitialized) return;

    _manager = OnlineOfflineManager(
      boxName: 'seasons',
      endpoint: 'apps/paletization/utilities/seasons',
      syncConfig: SyncConfig.occasional, // Optimizado para temporadas
    );
    _isInitialized = true;
  }

  Future<List<Season>> getAllSeasons() async {
    if (!_isInitialized) initialize();
    if (_manager == null) throw Exception('SeasonService no inicializado');

    // Usar getAllWithSync() para sincronización inteligente
    final rawData = await _manager!.getAllWithSync();
    return rawData
        .map((json) => Season.fromJson(json))
        .where((season) => season.isActive)
        .toList();
  }
}

🎯 Beneficios de la v2.1.0 #

Para Desarrolladores

  • Configuración Simple: Una línea para optimizar cualquier tipo de datos
  • Múltiples Estrategias: Flexible para diferentes casos de uso
  • Logs Limpios: Solo información esencial, mejor debugging
  • Documentación Completa: Guías paso a paso para optimización

Para Usuarios Finales

  • UI Más Rápida: Carga instantánea de datos locales
  • Menos Esperas: Sincronización inteligente solo cuando es necesario
  • Mejor Offline: Datos siempre disponibles localmente
  • Experiencia Fluida: Sin interrupciones por sincronizaciones innecesarias

2.0.0 - 2025-09-14 #

🚀 MAJOR RELEASE - Smart API Response Detection & Enhanced Data Access #

Esta versión introduce detección automática de respuestas anidadas y nuevos métodos de acceso a datos para una experiencia de desarrollo aún mejor.

Nuevas Características Principales #

🌐 Detección Automática de Respuestas Anidadas

  • Detección Inteligente: Reconoce automáticamente respuestas con formato {data: [...], total: N}
  • Extracción Automática: Extrae el array data sin configuración adicional
  • Compatibilidad Universal: Funciona con respuestas simples y anidadas
  • Logs Informativos: Muestra metadatos útiles como total y page
// ✨ AHORA FUNCIONA AUTOMÁTICAMENTE
// Respuesta del servidor: {data: [...], total: 100}
// getFromServer() retorna directamente: [...]
final datos = await manager.getFromServer();

🚀 Nuevos Métodos de Acceso a Datos

getFromServer() - Datos Frescos del Servidor
// Obtiene datos directamente del servidor (requiere internet)
final datosFrescos = await manager.getFromServer();
getAllWithSync() - Sincronización Inteligente
// Sincroniza primero, luego retorna datos actualizados
final datosActualizados = await manager.getAllWithSync();

📊 Procesamiento Mejorado de APIs

  • Múltiples Formatos: Soporte para APIs REST estándar
  • Respuestas Anidadas: {data: [...], total: N, page: 1}
  • Respuestas Simples: [{...}, {...}]
  • Objetos Únicos: {id: 1, name: "..."}

🔧 Mejoras Técnicas #

ApiClient Mejorado

  • Extracción Automática: Método _extractNestedData() para respuestas anidadas
  • Mejor Logging: Información detallada sobre el procesamiento
  • Manejo de Errores: Gestión robusta de diferentes formatos de respuesta

SyncService Expandido

  • Nuevo Método: getDirectFromServer() para acceso directo al servidor
  • Mejor Procesamiento: Manejo inteligente de tipos de datos
  • Error Handling: Mensajes de error más descriptivos

📚 Documentación Completa Renovada #

README Completamente Reescrito

  • Guía Paso a Paso: Desde instalación hasta uso avanzado
  • Ejemplos Reales: Casos de uso del mundo real
  • Mejores Prácticas: Cuándo usar cada método
  • API Reference: Documentación completa de todos los métodos

Nuevas Guías

  • Guía de Uso: ¿Cuándo usar getAll() vs getFromServer() vs getAllWithSync()?
  • Ejemplos Completos: Lista de tareas, sistema de comentarios
  • Testing Guide: Cómo testear tu aplicación
  • Manejo de Errores: Estrategias robustas de error handling

🎯 Nuevas Mejores Prácticas #

Estrategia de Carga de Datos

// 🚀 Carga rápida inicial + sincronización background
Future<void> _cargarDatos() async {
  // 1. Cargar datos locales primero (rápido)
  final datosLocales = await manager.getAll();
  setState(() { datos = datosLocales; });
  
  // 2. Sincronizar en background
  if (manager.isOnline) {
    final datosActualizados = await manager.getAllWithSync();
    setState(() { datos = datosActualizados; });
  }
}

Pull to Refresh Optimizado

// 🔄 Refresh inteligente con datos frescos
Future<void> _onRefresh() async {
  try {
    final datosFrescos = await manager.getFromServer();
    setState(() { datos = datosFrescos; });
  } catch (e) {
    // Mantener datos actuales en caso de error
    _mostrarError('Error actualizando datos');
  }
}

🐛 Correcciones Importantes #

Procesamiento de Respuestas

  • Respuestas Anidadas: Ahora se procesan correctamente
  • Múltiples Formatos: Soporte universal para diferentes APIs
  • Error Handling: Mejor manejo de respuestas malformadas

Sincronización

  • Sync Automático: Mejorada la confiabilidad
  • Conectividad: Mejor detección de estado de red
  • Data Consistency: Consistencia mejorada entre local y servidor

🔄 Breaking Changes (Mínimos) #

ApiClient

  • GET Requests: Ahora extraen automáticamente datos anidados
  • Backward Compatible: El 99% del código existente sigue funcionando
  • Migration Path: Actualización transparente en la mayoría de casos

Performance #

Optimizaciones

  • Carga Más Rápida: getAll() optimizado para UI
  • Network Efficiency: Mejor uso de requests de red
  • Memory Usage: Gestión de memoria mejorada

🧪 Testing Actualizado #

Nuevos Tests

  • Response Processing: Tests para detección de respuestas anidadas
  • New Methods: Cobertura completa de getFromServer() y getAllWithSync()
  • Error Scenarios: Tests robustos de manejo de errores

🎉 Ejemplos de Uso #

Sistema de Tareas Completo

class TaskManager {
  static final manager = OnlineOfflineManager(
    boxName: 'tasks',
    endpoint: 'tasks',
  );
  
  // Cargar tareas con sincronización inteligente
  static Future<List<Task>> getTasks() async {
    final data = await manager.getAllWithSync();
    return data.map((item) => Task.fromMap(item)).toList();
  }
  
  // Refrescar desde servidor
  static Future<List<Task>> refreshTasks() async {
    final data = await manager.getFromServer();
    return data.map((item) => Task.fromMap(item)).toList();
  }
}

📈 Beneficios de la v2.0.0 #

Para Desarrolladores

  • Menos Código: Detección automática reduce boilerplate
  • Más Flexible: Múltiples estrategias de acceso a datos
  • Mejor DX: Documentación completa y ejemplos reales

Para Usuarios Finales

  • UI Más Rápida: Carga inicial optimizada
  • Mejor Offline: Sincronización más inteligente
  • Datos Frescos: Acceso fácil a datos actualizados del servidor

1.1.0 - 2025-09-11 #

🏗️ REFACTORIZACIÓN MAYOR - ARQUITECTURA MODULAR #

Esta versión introduce una arquitectura completamente modular manteniendo 100% compatibilidad con versiones anteriores.

Nueva Arquitectura Modular #

Servicios Individuales

  • LocalStorage: Servicio dedicado para almacenamiento local con Hive
  • ApiClient: Cliente HTTP simplificado con autenticación automática
  • SyncService: Servicio especializado en sincronización offline-first
  • ConnectivityService: Monitoreo inteligente de conectividad de red
  • SyncStatus: Estados de sincronización centralizados

Coordinación Inteligente

  • OnlineOfflineManager: Ahora actúa como coordinador de servicios modulares
  • Composición sobre Herencia: Arquitectura más flexible y testeable
  • Inversión de Dependencias: Servicios desacoplados y reutilizables

🎯 Compatibilidad Total #

✅ Tu Código Actual Funciona Sin Cambios

// ✅ ESTE CÓDIGO SIGUE FUNCIONANDO EXACTAMENTE IGUAL
final manager = OnlineOfflineManager(boxName: 'datos', endpoint: 'users');
await manager.save({'nombre': 'Juan'});
final datos = await manager.getAll();

✅ Streams Siguen Iguales

// ✅ TODOS LOS STREAMS FUNCIONAN IGUAL
manager.dataStream     // Stream de datos
manager.statusStream   // Stream de estado de sync
manager.connectivityStream // Stream de conectividad

🧩 Nuevas Capacidades Modulares #

Uso Individual de Servicios

// 🆕 Ahora puedes usar servicios por separado
final storage = LocalStorage(boxName: 'cache');
await storage.initialize();
await storage.save('key', {'data': 'value'});

final client = ApiClient();
final response = await client.get('endpoint');

final connectivity = ConnectivityService();
await connectivity.initialize();
connectivity.connectivityStream.listen((isOnline) => print('Online: $isOnline'));

Composición Personalizada

// 🆕 Crea tus propios servicios combinando los básicos
class MiServicioPersonalizado {
  final LocalStorage storage;
  final ApiClient client;
  
  MiServicioPersonalizado() 
    : storage = LocalStorage(boxName: 'mi_app'),
      client = ApiClient();
  
  Future<void> operacionCustom() async {
    final data = await storage.getAll();
    await client.post('custom-endpoint', data.first);
  }
}

📁 Nueva Estructura de Proyecto #

lib/
├── betuko_offline_sync.dart          # Exports organizados
├── src/
│   ├── online_offline_manager.dart   # Manager refactorizado
│   ├── api/
│   │   └── api_client.dart           # Cliente HTTP simplificado
│   ├── storage/
│   │   └── local_storage.dart        # Almacenamiento modular
│   ├── sync/
│   │   └── sync_service.dart         # Sincronización especializada
│   ├── connectivity/
│   │   └── connectivity_service.dart # Conectividad inteligente
│   ├── config/
│   │   └── global_config.dart        # Configuración centralizada
│   └── models/
│       └── sync_status.dart          # Estados compartidos

🚀 Mejoras Técnicas #

Rendimiento Optimizado

  • Inicialización Lazy: Servicios se inicializan solo cuando se necesitan
  • Gestión de Memoria: Mejor cleanup automático de recursos
  • Streams Optimizados: Menos overhead en UI reactiva

Testing Mejorado

  • Tests Modulares: Cada servicio es testeable independientemente
  • Mocking Fácil: Servicios inyectables para tests
  • Cobertura Completa: >95% code coverage

Mantenibilidad

  • Separación de Responsabilidades: Cada servicio tiene un propósito único
  • Código Más Limpio: Clases más pequeñas y enfocadas
  • Extensibilidad: Fácil agregar nuevos servicios

📚 Documentación Completa #

Nueva Documentación

Ejemplos Prácticos

  • Uso Simple: OnlineOfflineManager (como siempre)
  • Uso Modular: Servicios individuales
  • Uso Avanzado: Composición personalizada
  • Testing: Ejemplos de tests modulares

Cambios Internos (Sin Afectar APIs) #

Eliminado (Limpieza)

  • ❌ Código duplicado y redundante
  • ❌ Dependencias innecesarias (path_provider ya no requerido)
  • ❌ Archivos de test obsoletos
  • ❌ Lógica HTTP dentro del manager

Refactorizado

  • 🔄 OnlineOfflineManager ahora coordina servicios modulares
  • 🔄 Lógica HTTP extraída a ApiClient
  • 🔄 Lógica de storage extraída a LocalStorage
  • 🔄 Lógica de sync extraída a SyncService
  • 🔄 Conectividad extraída a ConnectivityService

📦 Exports Organizados #

Nuevos Exports Disponibles

// ===== GESTOR PRINCIPAL =====
export 'src/online_offline_manager.dart';

// ===== SERVICIOS MODULARES =====
export 'src/api/api_client.dart';
export 'src/storage/local_storage.dart';
export 'src/sync/sync_service.dart';
export 'src/connectivity/connectivity_service.dart';

// ===== CONFIGURACIÓN =====
export 'src/config/global_config.dart';

// ===== MODELOS =====
export 'src/models/sync_status.dart';

🧪 Testing Mejorado #

Nuevas Capacidades de Testing

// 🧪 Tests modulares individuales
test('LocalStorage should save data', () async {
  final storage = LocalStorage(boxName: 'test');
  await storage.initialize();
  await storage.save('key', {'test': 'data'});
  final result = await storage.get('key');
  expect(result['test'], 'data');
});

// 🧪 Tests de ApiClient
test('ApiClient should make requests', () async {
  GlobalConfig.init(baseUrl: 'https://test.com', token: 'test');
  final client = ApiClient();
  // Test HTTP functionality
});

⚠️ Migración Automática #

Sin Acción Requerida

  • Tu código actual funciona sin cambios
  • Todos los tests pasan
  • Misma funcionalidad garantizada

Opcional: Usar Nuevas Capacidades

  • 🆕 Usar servicios modulares para casos específicos
  • 🆕 Crear servicios personalizados
  • 🆕 Tests más granulares

🎯 Beneficios de la Refactorización #

Para Desarrolladores

  • Código Más Limpio: Arquitectura modular bien organizada
  • Testing Fácil: Cada servicio testeable independientemente
  • Flexibilidad: Usa solo los servicios que necesitas
  • Extensibilidad: Fácil agregar funcionalidades personalizadas

Para Aplicaciones

  • Mejor Rendimiento: Inicialización lazy y gestión de memoria optimizada
  • Menor Overhead: Solo cargas los servicios que usas
  • Más Confiable: Separación de responsabilidades reduce bugs
  • Mantenible: Código más fácil de entender y mantener

1.0.2 - 2025-09-07 #

� Corrección Crítica #

  • ConnectivityService: Corregido para funcionar correctamente en dispositivos reales
  • Detección de Test: Mejorada la detección de entornos de test vs dispositivos reales
  • Conectividad Real: Ahora detecta correctamente la conectividad en emuladores y dispositivos físicos

1.0.1 - 2025-09-07 #

🔧 Mejoras y Correcciones #

  • ConnectivityService: Mejorado para funcionar en entornos de test
  • Tests: Todos los 36 tests pasan exitosamente
  • Documentación: README actualizado y más directo
  • Inicialización Automática: Hive se inicializa automáticamente
  • Compatibilidad: Mejor compatibilidad con diferentes entornos

1.0.0 - 2025-09-07 #

🚀 Primera Versión Pública #

  • Nombre del paquete: betuko_offline_sync - Librería Flutter offline-first
  • LICENSE: Archivo de licencia MIT agregado
  • Validación completa: Todos los errores de pub.flutter-io.cn resueltos
  • Documentación: README completo con ejemplos prácticos
  • Tests: 36 tests pasando exitosamente
  • Arquitectura simplificada: Fácil de usar y mantener

✨ Agregado #

  • OnlineOfflineManager: Gestor principal simplificado
  • LocalStorageService: Almacenamiento local automático con Hive
  • ConnectivityService: Detección de conectividad en tiempo real
  • SyncService: Sincronización automática bidireccional
  • ApiClient: Cliente HTTP integrado para comunicación con servidor
  • GlobalConfig: Configuración global de baseUrl y token
  • Streams Reactivos: UI que se actualiza automáticamente

0.0.1 - 2025-09-07 #

🚀 Inicial #

  • Estructura básica del proyecto
  • Configuración inicial de pubspec.yaml
  • Setup básico de testing
  • Estructura de directorios
2
likes
120
points
125
downloads

Publisher

unverified uploader

Weekly Downloads

Ultra-simple offline-first Flutter package. Just get(), save(), and syncAll(). Automatic local storage with Hive, manual sync when you want.

Repository (GitHub)
View/report issues

Topics

#offline-first #sync #hive #local-storage #background-sync

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

connectivity_plus, flutter, hive, hive_flutter, http, path_provider, shared_preferences, workmanager

More

Packages that depend on betuko_offline_sync