Background Syncing

Applications often need to sync data when they’re not in active use. This document explains background syncing implementations with PowerSync.

Platform Support

Background syncing has been tested in:

These examples can be adapted for other frameworks like React Native. For implementation questions or assistance, chat to us on Discord.

Flutter Implementation Guide

Prerequisites

  1. Complete the workmanager platform setup
  2. Review the Supabase To-Do List Demo for context

Configure the Background Task

In main.dart:

void main() async {
  // ... existing setup code ...
  
  const simpleTaskKey = "com.domain.myapp.taskId";
  
  // Mandatory if the App is obfuscated or using Flutter 3.1+
  ('vm:entry-point')
  void callbackDispatcher() {
    Workmanager().executeTask((task, inputData) async {
      switch (task) {
        case simpleTaskKey:
          // Initialize PowerSync database and connection
          final currentConnector = await openDatabase();
          db.connect(connector: currentConnector!);
          
          // Perform database operations
          await TodoList.create('New background task item');
          await currentConnector.uploadData(db);
          await TodoList.create('testing1111');
          await currentConnector.uploadData(db);
          // print("$simpleTaskKey was executed. inputData = $inputData");
          break;
      }
      // Close database when done
      await db.close();
      return Future.value(true);
    });
  }

  // Initialize the workmanager with your callback
  Workmanager().initialize(
    callbackDispatcher,
    // Shows notifications during task execution (useful for debugging)
    isInDebugMode: true
  );
  
  // ... rest of your app initialization ...
}

Note specifically in the switch statement:

// currentConnector is the connector to the remote DB
// openDatabase sets the db variable to the PowerSync database
final currentConnector = await openDatabase();
// connect PowerSync to the remote database
db.connect(connector: currentConnector!);
// a database write operation
await TodoList.create('Buy new shoes');
// Sync with the remote database
await currentConnector.uploadData(db);
  1. Since WorkManager executes in a new process, you need to set up the PowerSync local database and connect to the remote database using your connector.
  2. Run a write (in the case of this demo app, we create a ‘todo list’)
  3. Make sure to run currentConnector.uploadData(db); so that the local write is uploaded to the remote database.

Testing

Add a test button:

  ElevatedButton(
  title: const Text("Start the Flutter background service"),
     onTap: () async {
        await Workmanager().cancelAll();
        // print("RUN BACKGROUND TASK");
        await Workmanager().registerOneOffTask(
        simpleTaskKey,
        simpleTaskKey,
        initialDelay: Duration(seconds: 10),
        inputData: <String, dynamic>{
        int': 1,
      },
    );
  },
),

Press the button, background the app, wait 10 seconds, then verify new records in the remote database.

Platform Compatibility

Android

  • Implementation works as expected.

iOS

  • At the time of writing (January 2024), we were only able to get part of this to work using the branch for [this PR](https://github.com/fluttercommunity/ flutter_workmanager/pull/511) into workmanager.
  • While testing we were not able to get iOS background fetching to work, however this is most likely an issue with the package.