flutter_continued_task 0.1.0 copy "flutter_continued_task: ^0.1.0" to clipboard
flutter_continued_task: ^0.1.0 copied to clipboard

A Flutter plugin to ensure process lifecycle continuation and progress synchronization during long-running tasks in background across Android and iOS.

flutter_continued_task #

pub package Platform License: MIT

A robust Flutter plugin to keep long-running tasks alive when the app moves to the background, preventing OS process suspension and socket reclamation while synchronizing progress to system notifications, lock screens, and Dynamic Island.


🌟 Why flutter_continued_task? #

When a mobile app moves to the background during long-running tasks (such as photo/video batch uploads, file synchronization, database migrations, or on-device AI inference):

  1. OS Process Suspension: iOS and Android rapidly suspend or kill background apps unless an ongoing task assertion or foreground service is explicitly held.
  2. High-Frequency IPC Thrashing: Rapid progress events (e.g. enqueueing 10+ items synchronously) can flood Flutter's MethodChannel and flicker native notifications (0/1 -> 0/2 -> ...).
  3. Lifecycle Edge Cases: Handling user cancel button taps on notifications, Android 6h dataSync timeouts, and app termination recovery requires complex boilerplate.

flutter_continued_task solves all of this with a zero-boilerplate high-level API (ContinuedTask.track) and a flexible low-level API (ContinuedTask.start).


✨ Features #

  • πŸ›‘οΈ Guaranteed Process Continuation: Prevents OS suspension and network reclamation in the background.
  • πŸ€– Android dataSync Foreground Service:
    • Ongoing system progress notifications (setProgress).
    • Native "Cancel" action button on notifications.
    • Automatic 6-hour timeout guard to prevent RemoteServiceException.
  • 🍎 iOS 26+ BGContinuedProcessingTask:
    • Native lock screen and Dynamic Island progress tracking.
    • Swift Package Manager (SPM) & CocoaPods dual support.
  • ⚑ Automated High-Frequency Coalescing (_drain): Synchronous rapid updates are coalesced into a single IPC call, preventing "0/1" flicker and starting immediately with true batch totals (e.g. "0/9").
  • πŸ”„ Smart Batch Life-Cycle Management:
    • 0 -> N: Automatically requests OS process assertion & starts foreground service.
    • N -> M: Automatically updates progress.
    • N -> 0: Guarantees 100% completion update (N/N) before stopping the service.
    • Mid-flight additions: Automatically increments the batch total if new items are queued.
  • πŸ”Œ Native State Recovery: Automatically pulls native state (assertionHeld, stopRequested) on app cold start.

πŸ“± Platform Support #

Platform Install Target Active Background Continuation Underlying Mechanism
Android Android 8.0+ (API 26+) Android 8.0+ (API 26+) ForegroundService (dataSync) with 6h guard
iOS iOS 13.0+ iOS 26.0+ BGContinuedProcessingTask & Lock Screen Progress

Note on Compatibility: Below runtime minimums (e.g. iOS < 26.0), ContinuedTask.start() gracefully returns false / no-op without throwing errors, letting tasks run normally in the foreground and pause naturally in the background. This fallback is runtime-only: building the iOS side requires Xcode 26 / the iOS 26 SDK, and your Android module must set minSdkVersion 26 or higher.


πŸ“¦ Installation #

Add flutter_continued_task to your pubspec.yaml:

dependencies:
  flutter_continued_task: ^0.1.0

πŸ› οΈ Platform Setup #

1. Android Setup (Zero-Config πŸŽ‰) #

No manual AndroidManifest.xml edits required!
All required permissions (FOREGROUND_SERVICE, FOREGROUND_SERVICE_DATA_SYNC, POST_NOTIFICATIONS) and the foreground service component are automatically merged into your final APK/AAB during the build.

Tip for Android 13+ (API 33+):
Progress notifications require runtime notification permission. The package ships a helper, so no extra dependency is needed:

final granted = await ContinuedTask.requestNotificationPermission();

It returns true immediately on iOS and on Android below API 33.


2. iOS Setup #

Run the built-in setup script from your project root to automatically configure ios/Runner/Info.plist:

dart run flutter_continued_task:setup

Option B: Manual Setup

Add UIBackgroundModes with processing and your task identifier to ios/Runner/Info.plist:

<key>UIBackgroundModes</key>
<array>
    <string>processing</string>
</array>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
    <!-- Must be prefixed with your app's bundle identifier. -->
    <string>com.your.bundle.id.continued_task</string>
</array>

πŸš€ Quickstart #

The easiest and most robust way. Create a tracker once, then simply call tracker.sync(remainingCount) whenever your queue changes. Everything else (lifecycle start/update/stop, progress calculation, microtask IPC coalescing) is completely automated.

1. Minimal (1-liner with auto progress formatting)

final tracker = ContinuedTask.track(
  title: 'Uploading Photos', // Auto-formats to "Uploading Photos (done/total)"
  onUserCancel: () => cancelUploads(),
);

2. Custom Title Formatting (titleBuilder)

final tracker = ContinuedTask.track(
  titleBuilder: (done, total) => '$done of $total photos uploaded',
  onUserCancel: () => cancelUploads(),
);

3. Custom Metadata & Notifications (baseConfig)

import 'package:flutter_continued_task/flutter_continued_task.dart';

class UploadService {
  late final TaskTracker _tracker;

  void initialize() {
    _tracker = ContinuedTask.track(
      title: 'Uploading Photos',
      baseConfig: const ContinuedTaskConfig(
        androidNotificationIcon: 'upload', // Built-in: 'upload', 'download', 'sync', 'processing'
        androidChannelName: 'Photo Uploads',
      ),
      onUserCancel: () async {
        print('User tapped cancel on notification!');
        // Stop or pause your internal work queue
      },
      onTimeout: () {
        print('OS timeout reached (Android 6h limit)');
      },
      onAssertionChanged: (held) {
        print('OS assertion active: $held');
      },
    );
  }

  /// Call this whenever your pending queue count changes:
  /// - 0 -> 9: Starts foreground task as "0/9" (no "0/1" flicker)
  /// - 9 -> 8: Updates progress to "1/9"
  /// - 1 -> 0: Sends final "9/9" update and automatically stops task (100% completed)
  Future<void> onQueueUpdated(int remainingCount) {
    return _tracker.sync(remainingCount);
  }

  /// Call this when the user cancels or aborts the entire batch mid-flight:
  Future<void> cancelQueue() {
    return _tracker.cancel();
  }

  void dispose() {
    _tracker.dispose();
  }
}

Approach 2: Low-Level API (ContinuedTask.start) #

If you want full manual control over start, update, and stop:

import 'package:flutter_continued_task/flutter_continued_task.dart';

// 1. Check platform support
if (!ContinuedTask.isSupported) return;

// 2. Start manual task
final task = await ContinuedTask.start(
  config: const ContinuedTaskConfig(
    taskId: 'custom_task_1',
    title: 'Processing Video',
    maxProgress: 100,
    allowCancel: true,
  ),
  onUserCancel: () => print('User canceled'),
  onTimeout: () => print('Timed out'),
  onAssertionChanged: (held) => print('Assertion: $held'),
);

// 3. Update progress (automatically serialized and throttled)
await task?.update(progress: 45, maxProgress: 100, subtitle: '45%');

// 4. Stop when finished
await task?.stop();

βš™οΈ Configuration Reference (ContinuedTaskConfig) #

All properties have sensible defaults and are completely optional:

Property Type Default Description
title String 'Task in progress' Main title displayed on notifications and lock screen.
subtitle String? null Secondary text or description.
allowCancel bool true Displays a user "Cancel" action button on the system notification.
cancelActionLabel String 'Cancel' Action button text.
androidNotificationIcon String? null Android notification icon resource or keyword ('upload', 'download', 'sync', 'processing').
androidChannelId String 'continued_task_channel' Android notification channel ID.
androidChannelName String 'Background Task' Android notification category name in OS settings.
androidChannelDescription String 'Shows ongoing progress...' Android notification channel description.
iosTaskIdentifier String? null iOS BGContinuedProcessingTask ID (must match Info.plist).
indeterminate bool false Shows an indeterminate spinner instead of a progress bar.

πŸ§ͺ Comprehensive Testing #

This package includes a standalone unit & integration test suite covering all lifecycle and concurrency scenarios:

flutter test

You can also run the interactive test dashboard in example/ (cd example && flutter run) to visually test rapid batch coalescing, mid-flight additions, and notification cancel actions on an emulator or real device.


πŸ“„ License #

MIT License. See LICENSE for details.

2
likes
0
points
272
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin to ensure process lifecycle continuation and progress synchronization during long-running tasks in background across Android and iOS.

Repository (GitHub)
View/report issues

Topics

#background #foreground-service #bgtaskscheduler #lifecycle

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_continued_task

Packages that implement flutter_continued_task