Skip to content

pocketsync/pocketsync_flutter

Repository files navigation

PocketSync Logo

Website · Documentation · Report Bug


PocketSync enables seamless data synchronization across devices without managing your own backend infrastructure. It works with SQLite databases and handles all the complexities of data synchronization for you.

Note: PocketSync is currently in alpha. The system is under active development and should not be considered reliable for production use. We are still yet to test it in production like conditions.

Features

  • Offline-first architecture: Continue working with your data even when offline
  • Automatic synchronization: Changes are automatically synchronized when connectivity is restored
  • Conflict resolution: Multiple built-in strategies for handling conflicts
  • Optimized change tracking: Efficiently tracks and batches changes to minimize network usage
  • SQLite integration: Built on top of SQLite for reliable local data storage
  • Customizable: Flexible configuration options to suit your specific needs

Installation

dependencies:
  pocketsync_flutter: latest

Then run:

flutter pub get

Quick start

You'll need to create a PocketSync project in the PocketSync dashboard and get your project ID, auth token, and server URL.

1. Initialize PocketSync

import 'package:pocketsync_flutter/pocketsync_flutter.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

Future<void> initPocketSync() async {
  // Get the database path
  String dbPath = join(await getDatabasesPath(), 'my_app_database.db');
  
  // Initialize PocketSync
  await PocketSync.initialize(
    options: PocketSyncOptions(
      projectId: 'YOUR_PROJECT_ID',
      authToken: 'YOUR_AUTH_TOKEN',
      serverUrl: 'https://api.pocketsync.dev',
      // Optional configurations
      conflictResolutionStrategy: ConflictResolutionStrategy.lastWriteWins,
      verbose: true,
    ),
    databaseOptions: DatabaseOptions(
      dbPath: dbPath,
      version: 1,
      schema: DatabaseSchema(
        tables: [
          TableSchema(
            name: 'todos',
            columns: [
              TableColumn.primaryKey(name: 'id', type: ColumnType.INTEGER),
              TableColumn.text(name: 'title'),
              TableColumn.boolean(name: 'isCompleted'),
            ],
          ),
        ],
      ),
    ),
  );

  // Authenticate
  PocketSync.instance.setUserId('my-user-id');
  
  // Start the sync engine
  await PocketSync.instance.start();
}

2. Use the PocketSync database

// Get a reference to the database
final db = PocketSync.instance.database;

// Insert data
await db.insert('todos', {
  'title': 'Buy groceries',
  'isCompleted': 0,
});

// Query data
List<Map<String, dynamic>> todos = await db.query('todos');

// Update data
await db.update(
  'todos',
  {'isCompleted': 1},
  where: 'id = ?',
  whereArgs: [1],
);

// Delete data
await db.delete('todos', where: 'id = ?', whereArgs: [1]);

// Watch database changes
final stream = db.watch('SELECT * FROM todos');
stream.listen((event) {
  print(event);
});

Read more: PocketSync Database

3. Manual sync control

// Manually trigger sync
await PocketSync.instance.scheduleSync();

// Pause synchronization
await PocketSync.instance.stop();

// Resume synchronization
await PocketSync.instance.start();

4. Conflict resolution

PocketSync provides several strategies for resolving conflicts:

  • Last Write Wins: The most recent change based on timestamp wins (default)
  • Server Wins: Server changes always take precedence
  • Client Wins: Local changes always take precedence
  • Custom: Provide your own conflict resolution logic
// Using a custom conflict resolver
await PocketSync.initialize(
  options: PocketSyncOptions(
    // ... other options
    conflictResolutionStrategy: ConflictResolutionStrategy.custom,
    customResolver: (localChange, remoteChange) async {
      // Your custom logic to decide which change wins
      return localChange.timestamp > remoteChange.timestamp
          ? localChange
          : remoteChange;
    },
  ),
  // ... database options
);

5. Advanced usage

User authentication

Set the user ID:

PocketSync.instance.setUserId('user123');

Note that this is required for sync to actually work. On the server side, the user ID is used to identify the user and their data.

Reset sync state

Clear all sync tracking data (use with caution):

await PocketSync.instance.reset();

Note: Call PocketSync.instance.reset() before calling PocketSync.instance.start() to reset the sync engine (for existing apps. Be cautious when using this method as it will clear all change tracking data). It runs once per plugin version (the goal is to provide a smooth transition for people that were using the sdk prior to version 0.3.0)

Dispose Resources

Clean up resources when the app is closing:

await PocketSync.instance.dispose();

Migration

From 0.4.2 to 0.5.0

  • PocketSync now uses the new schema system to define your database schema. This change is interesting because it enables a set of features that were not possible before. Our your end, it helps you to define your database schema in a more type-safe way.

From 0.2.0 to 0.3.0

  • PocketSync now uses SQLite FFI to fix issues with JSON_OBJECT function not being available on some Android devices
  • The implementation uses sqflite_common_ffi and sqlite3_flutter_libs packages to provide a more recent version of SQLite with JSON function support
  • A SqliteFfiHelper class was created to initialize the FFI implementation before database operations
  • Call PocketSync.instance.reset() before calling PocketSync.instance.start() to reset the sync engine.

Best practices

  1. Initialize early: Initialize PocketSync during app startup
  2. Handle conflicts: Choose an appropriate conflict resolution strategy for your app
  3. Batch operations: Group related database operations to optimize sync performance
  4. User authentication: Set the user ID when the user logs in (sync will not work without a user ID)

Support

If you have any questions or need help, please open an issue on the GitHub repository.

If you need to talk to the PocketSync team, please reach out to hello@pocketsync.dev.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Packages

No packages published

Languages