Skip to content

Harsh4114/Offline_sync_engine_doc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 

Repository files navigation

Offline Sync Flutter App

Flutter + Hive + Firebase Realtime Database + Connectivity Plus

This project demonstrates how to build an offline-first Flutter app using:

  • offline_sync_engine
  • Hive (local storage)
  • Firebase Realtime Database (cloud backend)
  • connectivity_plus (internet detection)

πŸš€ Features

  • Offline data creation, update, and deletion
  • Automatic sync when internet reconnects
  • Local operation tracking using Hive
  • Cloud synchronization using Firebase
  • Device-aware sync using UUID

πŸ“¦ Dependencies

Add these to pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  offline_sync_engine: ^2.3.0
  hive: ^2.2.3
  hive_flutter: ^1.1.0
  firebase_core: ^2.8.0
  firebase_database: ^10.0.15
  connectivity_plus: ^6.1.4
  uuid: ^4.1.0

dev_dependencies:
  build_runner: ^2.4.8

Or

Run:

flutter pub add uuid connectivity_plus firebase_database firebase_core offline_sync_engine hive hive_flutter ;
flutter pub get ;

πŸ”₯ Firebase Setup

  1. Create project in Firebase Console

  2. Enable Realtime Database

  3. Add:

    • google-services.json (Android)
    • GoogleService-Info.plist (iOS)
  4. Initialize Firebase in main.dart:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

🧩 Data Model Example

class Note {
  final String id;
  final String content;

  Note({required this.id, required this.content});

  Map<String, dynamic> toJson() => {
        'id': id,
        'content': content,
      };

  factory Note.fromJson(Map<String, dynamic> json) {
    return Note(
      id: json['id'],
      content: json['content'],
    );
  }
}

πŸ’Ύ Hive Database Adapter

class HiveDatabaseAdapter implements DatabaseAdapter {
  final Box _opBox;

  HiveDatabaseAdapter(this._opBox);

  @override
  Future<void> saveOperation(SyncOperation op) async {
    await _opBox.put(op.opId, op.toJson());
  }

  @override
  Future<List<SyncOperation>> getUnsentOperations() async {
    return _opBox.values
        .map((e) => SyncOperation.fromJson(Map<String, dynamic>.from(e)))
        .toList();
  }

  @override
  Future<void> markOperationSent(String opId) async {
    await _opBox.delete(opId);
  }

  @override
  Future<bool> isApplied(String opId) async {
    return !_opBox.containsKey(opId);
  }

  @override
  Future<void> applyOperation(SyncOperation operation) async {
    await markOperationSent(operation.opId);
  }

  @override
  Future<SyncRecord?> getRecord(String id) async {
    return null;
  }
}

Hive Initialization

await Hive.initFlutter();
final opBox = await Hive.openBox('sync_operations');
final syncDbAdapter = HiveDatabaseAdapter(opBox);

☁️ Firebase Cloud Adapter

class FirebaseCloudAdapter implements CloudAdapter {
  final DatabaseReference dbRef;

  FirebaseCloudAdapter(this.dbRef);

  @override
  Future<void> push(List<SyncOperation> ops) async {
    for (final op in ops) {
      await dbRef.child('operations/${op.opId}').set(op.toJson());
    }
  }

  @override
  Future<List<SyncOperation>> pull() async {
    final snapshot = await dbRef.child('operations').get();
    if (!snapshot.exists) return [];

    final data = Map<String, dynamic>.from(snapshot.value as Map);

    return data.values
        .map((e) => SyncOperation.fromJson(Map<String, dynamic>.from(e)))
        .toList();
  }
}

πŸ”„ SyncManager Setup

final syncManager = SyncManager(
  database: syncDbAdapter,
  cloud: cloudAdapter,
  deviceId: const Uuid().v4(),
);

🌐 Internet Connectivity Listener

Connectivity().onConnectivityChanged.listen((result) async {
  if (result != ConnectivityResult.none) {
    await syncManager.sync();
  }
});

✏️ Create / Update / Delete

Create or Update

final id = const Uuid().v4();

await syncManager.createOrUpdate(id, {
  'id': id,
  'content': 'My offline-first note',
});

Delete

await syncManager.delete(id);

πŸ§ͺ Testing Flow

  1. Turn off internet
  2. Create or update notes
  3. Turn internet back on
  4. Sync runs automatically
  5. Verify data in Firebase Realtime Database

πŸ— Architecture Overview

Component Responsibility
HiveDatabaseAdapter Stores operations locally
FirebaseCloudAdapter Pushes & pulls cloud data
SyncManager Handles sync logic
Connectivity Plus Detects network changes

⚠️ Production Considerations

  • Add proper conflict resolution
  • Implement batching
  • Add error handling & retries
  • Secure Firebase rules
  • Clean up synced operations

πŸ“Œ Summary

This example demonstrates a complete offline-first architecture using:

  • Local-first writes
  • Operation tracking
  • Cloud synchronization
  • Automatic reconnection handling

This structure is scalable and suitable for real-world apps requiring offline support.

About

offline_sync_engine is a Flutter package for building offline-first apps by tracking local create, update, and delete operations and syncing them with a remote backend using custom local storage (e.g., Hive) and cloud adapters (e.g., Firebase),

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors