background_guard 1.0.3 copy "background_guard: ^1.0.3" to clipboard
background_guard: ^1.0.3 copied to clipboard

Diagnose why background tasks fail on Android, guide users to fix system restrictions, and verify the fix worked.

example/lib/main.dart

import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:background_guard/background_guard.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await _initBackgroundGuard();
  runApp(const MyApp());
}

Future<void> _initBackgroundGuard() async {
  if (Platform.isAndroid) {
    // Android-only init (WorkManager etc.)
    await BackgroundGuard.init();
    return;
  }

  if (Platform.isIOS) {
    // Start probe lazily from UI, or optionally start here if you want:
    await IosProbe.start();
    return;
  }

  // Other platforms (web/desktop) - do nothing by design.
  if (kDebugMode) {
    debugPrint('BackgroundGuard: init skipped (unsupported platform).');
  }
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // ---------------- ANDROID STATE  ----------------

  Map<String, Object?> _health = const {};
  DeviceReport? _report;
  String? _lastFixResult;

  // ---------------- iOS STATE ----------------
  String _iosLogs = '—';
  String? _iosStatus;

  // ---------------- ANDROID ACTIONS (UNCHANGED) ----------------

  Future<void> _runNow() async {
    await BackgroundGuard.runHeartbeatNow();
    await Future.delayed(const Duration(seconds: 2));
    await _readHealth();
  }

  Future<void> _schedulePeriodic() async {
    await BackgroundGuard.scheduleHeartbeat(periodicTimeInMinutes: 3);
  }

  Future<void> _readHealth() async {
    final h = await BackgroundGuard.debugReadHealth();
    setState(() => _health = h);
  }

  Future<void> _checkDevice() async {
    final r = await BackgroundGuard.checkDevice();
    setState(() {
      _report = r;
      _lastFixResult = null;
    });
  }

  Future<void> _openFix(FixAction action) async {
    setState(() => _lastFixResult = null);
    final ok = await BackgroundGuard.openFix(action);
    setState(() {
      _lastFixResult = ok
          ? 'Opened: ${action.title}'
          : 'Could not open: ${action.title} (OEM action may be coming next)';
    });
  }

  String _fmtMillis(Object? millis) {
    if (millis is! int) return '—';
    return DateTime.fromMillisecondsSinceEpoch(millis).toLocal().toString();
  }

  // ---------------- iOS ACTIONS ----------------

  Future<void> _iosStartProbe() async {
    final ok = await IosProbe.start();
    setState(() {
      _iosStatus = ok
          ? 'Probe started. Export logs to view.'
          : 'Probe start failed.';
    });
  }

  Future<void> _iosScheduleRefresh() async {
    final ok = await IosProbe.scheduleRefresh();
    setState(() {
      _iosStatus = ok
          ? 'Schedule submitted (best-effort by iOS). Export logs.'
          : 'Schedule failed (see exported logs).';
    });
  }

  Future<void> _iosExportLogs() async {
    final logs = await IosProbe.exportLogs();
    setState(() {
      _iosLogs = logs.isEmpty ? 'No logs yet.' : logs;
    });
  }

  @override
  Widget build(BuildContext context) {
    // ✅ If iOS -> show iOS UI
    if (Platform.isIOS) {
      return MaterialApp(
        home: Scaffold(
          appBar: AppBar(title: const Text('BackgroundGuard Demo (iOS)')),
          body: ListView(
            padding: const EdgeInsets.all(16),
            children: [
              const Text(
                'iOS Probe (Barebones)',
                style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 8),
              const Text(
                'iOS does not support Android-style background fixing. '
                'This probe focuses on observability and exporting logs.',
              ),
              const SizedBox(height: 16),

              ElevatedButton(
                onPressed: _iosStartProbe,
                child: const Text('Start iOS Probe'),
              ),
              const SizedBox(height: 10),

              ElevatedButton(
                onPressed: _iosScheduleRefresh,
                child: const Text('Schedule BG Refresh (best-effort)'),
              ),
              const SizedBox(height: 10),

              OutlinedButton(
                onPressed: _iosExportLogs,
                child: const Text('Export Logs'),
              ),

              const SizedBox(height: 14),

              if (_iosStatus != null)
                Container(
                  padding: const EdgeInsets.all(12),
                  decoration: BoxDecoration(
                    border: Border.all(color: Colors.black12),
                    borderRadius: BorderRadius.circular(10),
                  ),
                  child: Text(_iosStatus!),
                ),

              const SizedBox(height: 12),

              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.black12),
                  borderRadius: BorderRadius.circular(10),
                ),
                child: Text(
                  _iosLogs,
                  style: const TextStyle(fontFamily: 'monospace'),
                ),
              ),
            ],
          ),
        ),
      );
    }

    // ✅ Else Android -> keep EXACT same UI

    final lastAttempt = _health['lastAttempt'];
    final lastSuccess = _health['lastSuccess'];
    final lastError = _health['lastError'];

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('BackgroundGuard Demo')),
        body: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            // ----- Background heartbeat demo -----
            const Text(
              'Background Execution',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            ElevatedButton(
              onPressed: _runNow,
              child: const Text('Run Heartbeat Now'),
            ),
            const SizedBox(height: 8),
            ElevatedButton(
              onPressed: _schedulePeriodic,
              child: const Text('Schedule Periodic Heartbeat '),
            ),
            const SizedBox(height: 8),
            OutlinedButton(
              onPressed: _readHealth,
              child: const Text('Read Health'),
            ),
            const SizedBox(height: 12),
            _kv('Last Attempt', _fmtMillis(lastAttempt)),
            _kv('Last Success', _fmtMillis(lastSuccess)),
            _kv('Last Error', (lastError as String?) ?? '—'),
            const Divider(height: 32),

            // ----- Device report demo -----
            const Text(
              'Device Report',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            ElevatedButton(
              onPressed: _checkDevice,
              child: const Text('Check Device'),
            ),
            const SizedBox(height: 12),

            if (_report == null)
              const Text('Press “Check Device” to generate a report.')
            else ...[
              _kv('Manufacturer', _report!.manufacturer),
              _kv('Model', _report!.model),
              _kv('Android SDK', _report!.sdkInt.toString()),
              _kv('Status', _report!.status.name),
              const SizedBox(height: 12),

              const Text(
                'Issues',
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
              ),
              const SizedBox(height: 6),
              if (_report!.issues.isEmpty)
                const Text('No issues detected.')
              else
                ..._report!.issues.map((e) => _bullet(e)),

              const SizedBox(height: 16),
              const Text(
                'Fix Actions',
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
              ),
              const SizedBox(height: 6),
              if (_report!.fixActions.isEmpty)
                const Text('No fix actions available.')
              else
                ..._report!.fixActions.map(
                  (a) => Padding(
                    padding: const EdgeInsets.only(bottom: 8),
                    child: OutlinedButton(
                      onPressed: () => _openFix(a),
                      child: Align(
                        alignment: Alignment.centerLeft,
                        child: Text(a.title),
                      ),
                    ),
                  ),
                ),

              if (_lastFixResult != null) ...[
                const SizedBox(height: 8),
                Text(
                  _lastFixResult!,
                  style: const TextStyle(fontStyle: FontStyle.italic),
                ),
              ],
            ],
          ],
        ),
      ),
    );
  }

  Widget _kv(String k, String v) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 6),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(
            width: 120,
            child: Text(
              '$k:',
              style: const TextStyle(fontWeight: FontWeight.w600),
            ),
          ),
          Expanded(child: Text(v)),
        ],
      ),
    );
  }

  Widget _bullet(String text) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 4),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text('•  '),
          Expanded(child: Text(text)),
        ],
      ),
    );
  }
}
2
likes
150
points
138
downloads

Publisher

verified publisherflutterjunction.com

Weekly Downloads

Diagnose why background tasks fail on Android, guide users to fix system restrictions, and verify the fix worked.

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

MIT (license)

Dependencies

device_info_plus, flutter, permission_handler, plugin_platform_interface, shared_preferences, workmanager

More

Packages that depend on background_guard

Packages that implement background_guard