flutter_lifecycle_guard 1.0.0-dev.1 copy "flutter_lifecycle_guard: ^1.0.0-dev.1" to clipboard
flutter_lifecycle_guard: ^1.0.0-dev.1 copied to clipboard

Reliable background execution for Flutter. Automatically manages foreground services, WorkManager, and iOS background tasks with built-in OEM battery saver evasion.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_lifecycle_guard/flutter_lifecycle_guard.dart';

import 'verification_harness_page.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await LifecycleGuard.initialize(
    config: LifecycleGuardConfig(
      androidNotificationChannelId: 'my_app_bg',
      androidNotificationChannelName: 'Background Sync',
      enableOemGuidance: true,
      autoRequestPermissions: true,
      enableDetailedLogging: true,
    ),
  );

  runApp(const MyApp());
}

// IMPORTANT: This must be a top-level function for background execution
@pragma('vm:entry-point')
Future<void> syncWithServer(ProgressCallback updateProgress) async {
  final items = await getUnsyncedItems();
  for (var i = 0; i < items.length; i++) {
    await uploadItem(items[i]);
    updateProgress((i + 1) / items.length);
  }
}

// Top-level heartbeat function
@pragma('vm:entry-point')
Future<void> periodicSync() async {
  final items = await getUnsyncedItems();
  if (items.isNotEmpty) {
    for (final item in items) {
      await uploadItem(item);
    }
  }
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: const HomePage());
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  GuardTaskHandle? _currentUpload;
  String _status = 'Idle';
  double _progress = 0;

  @override
  void initState() {
    super.initState();
    _setupHeartbeat();
    _checkOemGuidance();
  }

  Future<void> _setupHeartbeat() async {
    await LifecycleGuard.instance.scheduleHeartbeat(
      HeartbeatConfig(
        id: 'periodic_sync',
        interval: const Duration(minutes: 30),
        work: periodicSync,
        constraints: TaskConstraints(requiresNetwork: true),
      ),
    );
  }

  Future<void> _checkOemGuidance() async {
    // Wait for the widget to be built
    await Future.delayed(const Duration(seconds: 2));

    final guide = LifecycleGuard.instance.oemGuide;
    if (guide != null && guide.severity.index >= OemSeverity.high.index) {
      if (mounted) {
        await LifecycleGuard.instance.showBatteryOptimizationSettings(
          context: context,
          showExplanationFirst: true,
        );
      }
    }
  }

  Future<void> _startUpload() async {
    final handle = await LifecycleGuard.instance.execute(
      TaskDescriptor(
        id: 'upload_photos_${DateTime.now().millisecondsSinceEpoch}',
        urgency: TaskUrgency.immediate,
        work: syncWithServer,
        notification: TaskNotification(
          title: 'Uploading photos',
          body: 'Syncing your photos to the cloud',
        ),
        constraints: TaskConstraints(requiresNetwork: true),
        serviceType: ForegroundServiceType.dataSync,
        retryPolicy: RetryPolicy(maxRetries: 3),
        onKilled: () {
          // Save progress for retry
          saveUploadCheckpoint();
        },
      ),
    );

    setState(() => _currentUpload = handle);

    handle.statusStream.listen((status) {
      if (mounted) {
        setState(() {
          _status = status.message;
          _progress = status.progress ?? 0;
        });
      }

      if (status.state == TaskState.completed) {
        if (mounted) {
          ScaffoldMessenger.of(
            context,
          ).showSnackBar(const SnackBar(content: Text('Upload complete!')));
        }
      }
    });
  }

  Future<void> _cancelUpload() async {
    await _currentUpload?.cancel();
    setState(() {
      _currentUpload = null;
      _status = 'Cancelled';
      _progress = 0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('LifecycleGuard Demo')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  children: [
                    Text(
                      'Status: $_status',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    LinearProgressIndicator(value: _progress),
                    const SizedBox(height: 4),
                    Text('${(_progress * 100).toStringAsFixed(0)}%'),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),
            ElevatedButton.icon(
              onPressed: _currentUpload == null ? _startUpload : null,
              icon: const Icon(Icons.cloud_upload),
              label: const Text('Start Background Upload'),
            ),
            const SizedBox(height: 8),
            OutlinedButton.icon(
              onPressed: _currentUpload != null ? _cancelUpload : null,
              icon: const Icon(Icons.cancel),
              label: const Text('Cancel Upload'),
            ),
            const SizedBox(height: 24),
            const Divider(),
            const SizedBox(height: 16),
            FilledButton.icon(
              onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute<void>(
                    builder: (_) => const VerificationHarnessPage(),
                  ),
                );
              },
              icon: const Icon(Icons.fact_check),
              label: const Text('Open QA Verification Harness'),
            ),
            const SizedBox(height: 16),
            Text('OEM Info', style: Theme.of(context).textTheme.titleMedium),
            const SizedBox(height: 8),
            Builder(
              builder: (context) {
                final guide = LifecycleGuard.instance.oemGuide;
                if (guide == null) {
                  return const Text('No OEM-specific restrictions detected.');
                }
                return Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('Manufacturer: ${guide.manufacturer}'),
                    Text('Severity: ${guide.severity.name}'),
                    Text(guide.description),
                    const SizedBox(height: 8),
                    ElevatedButton(
                      onPressed: () {
                        LifecycleGuard.instance.showBatteryOptimizationSettings(
                          context: context,
                        );
                      },
                      child: const Text('Open Battery Settings'),
                    ),
                  ],
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

// Stub functions for the example
Future<List<String>> getUnsyncedItems() async => ['item1', 'item2', 'item3'];
Future<void> uploadItem(String item) async =>
    await Future.delayed(const Duration(seconds: 2));
void saveUploadCheckpoint() {}
1
likes
150
points
45
downloads

Publisher

verified publisherthesanaullah.dev

Weekly Downloads

Reliable background execution for Flutter. Automatically manages foreground services, WorkManager, and iOS background tasks with built-in OEM battery saver evasion.

Repository (GitHub)
View/report issues

Topics

#background-tasks #workmanager #foreground-service #lifecycle #battery-optimization

Documentation

API reference

Funding

Consider supporting this project:

buymeacoffee.com

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flutter_lifecycle_guard

Packages that implement flutter_lifecycle_guard