Flutter'da Arka Plan Görevleri: WorkManager ve Isolate

Flutter uygulamaları uygulama arka plandayken veya kapalıyken de görev çalıştırabilir. Üç farklı yaklaşım mevcuttur: WorkManager (periyodik ve tek seferlik arka plan görevleri), Dart Isolate (UI thread'i bloke etmeden paralel işlem) ve flutter_background_service (uzun süreli foreground servis).

WorkManager: Periyodik Arka Plan Görevleri

// pubspec: workmanager: ^0.5.2

// main.dart — WorkManager başlatma
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await WorkManager().initialize(
    callbackDispatcher,
    isInDebugMode: kDebugMode,
  );
  runApp(const MyApp());
}

// Top-level fonksiyon — ayrı isolate'de çalışır
@pragma('vm:entry-point')
void callbackDispatcher() {
  WorkManager().executeTask((taskName, inputData) async {
    switch (taskName) {
      case 'syncData':
        return _syncData(inputData);
      case 'cleanCache':
        return _cleanCache();
      case 'sendAnalytics':
        return _sendAnalytics(inputData);
      default:
        return Future.value(false);
    }
  });
}

Future<bool> _syncData(Map<String, dynamic>? input) async {
  try {
    // Flutter bağımlılıkları başlat
    final prefs = await SharedPreferences.getInstance();
    final token = prefs.getString('auth_token');
    if (token == null) return true; // kullanıcı giriş yapmamış

    final dio = Dio();
    final response = await dio.get(
      'https://api.example.com/sync',
      options: Options(headers: {'Authorization': 'Bearer $token'}),
    );

    // Verileri kaydet
    await prefs.setString('last_sync', DateTime.now().toIso8601String());
    await prefs.setString('sync_data', jsonEncode(response.data));
    return true;
  } catch (e) {
    debugPrint('Senkronizasyon hatası: $e');
    return false; // WorkManager görevi başarısız olarak işaretler
  }
}

// Görev kaydetme
class BackgroundTaskService {
  // Her 15 dakikada bir (minimum interval)
  static Future<void> registerPeriodicSync() =>
      WorkManager().registerPeriodicTask(
        'periodic-sync',
        'syncData',
        frequency: const Duration(hours: 1),
        initialDelay: const Duration(minutes: 5),
        constraints: Constraints(
          networkType: NetworkType.connected,
          requiresBatteryNotLow: true,
        ),
        existingWorkPolicy: ExistingWorkPolicy.replace,
      );

  // Tek seferlik görev
  static Future<void> scheduleOneTimeClean() =>
      WorkManager().registerOneOffTask(
        'one-off-clean',
        'cleanCache',
        initialDelay: const Duration(hours: 24),
        constraints: Constraints(requiresDeviceIdle: true),
      );

  // Görevi iptal et
  static Future<void> cancelSync() =>
      WorkManager().cancelByUniqueName('periodic-sync');

  // Tüm görevleri iptal et
  static Future<void> cancelAll() => WorkManager().cancelAll();
}

Dart Isolate: UI Thread'i Bloke Etmeden Ağır İşlem

import 'dart:isolate';

// Basit işlemler için compute() yeterli
Future<List<Product>> parseProducts(String json) =>
    compute(_parseIsolate, json);

List<Product> _parseIsolate(String json) =>
    (jsonDecode(json) as List).map((e) => Product.fromJson(e)).toList();

// Daha kompleks, çift yönlü iletişim için ham Isolate
class ImageProcessingIsolate {
  late Isolate _isolate;
  late SendPort _sendPort;
  final _receivePort = ReceivePort();
  final _resultController = StreamController<ProcessedImage>.broadcast();

  Stream<ProcessedImage> get results => _resultController.stream;

  Future<void> start() async {
    _isolate = await Isolate.spawn(_isolateEntry, _receivePort.sendPort);
    _sendPort = await _receivePort.first as SendPort;

    _receivePort.skip(1).listen((msg) {
      if (msg is ProcessedImage) _resultController.add(msg);
    });
  }

  void processImage(Uint8List imageBytes, ImageFilter filter) {
    _sendPort.send({'bytes': imageBytes, 'filter': filter.name});
  }

  void dispose() {
    _isolate.kill(priority: Isolate.immediate);
    _receivePort.close();
    _resultController.close();
  }
}

@pragma('vm:entry-point')
void _isolateEntry(SendPort mainSendPort) async {
  final receivePort = ReceivePort();
  mainSendPort.send(receivePort.sendPort);

  await for (final msg in receivePort) {
    final map = msg as Map<String, dynamic>;
    final bytes = map['bytes'] as Uint8List;
    final filterName = map['filter'] as String;

    // Ağır görüntü işleme
    final processed = await _applyFilter(bytes, ImageFilter.fromName(filterName));
    mainSendPort.send(processed);
  }
}

// Isolate havuzu — birden fazla paralel görev
class IsolatePool {
  final int _size;
  final List<IsolateWorker> _workers = [];
  int _roundRobin = 0;

  IsolatePool(this._size);

  Future<void> initialize() async {
    for (var i = 0; i < _size; i++) {
      final worker = IsolateWorker();
      await worker.start();
      _workers.add(worker);
    }
  }

  Future<T> run<T>(Future<T> Function() task) {
    final worker = _workers[_roundRobin % _size];
    _roundRobin++;
    return worker.execute(task);
  }
}

flutter_background_service: Uzun Süreli Servis

// pubspec: flutter_background_service: ^5.0.5

// main.dart
Future<void> initBackgroundService() async {
  final service = FlutterBackgroundService();

  await service.configure(
    androidConfiguration: AndroidConfiguration(
      onStart: onBackgroundServiceStart,
      autoStart: false,
      isForegroundMode: true, // foreground service — kullanıcıya bildirim gösterir
      notificationChannelId: 'background_service',
      initialNotificationTitle: 'Uygulama Çalışıyor',
      initialNotificationContent: 'Arka planda çalışıyor',
      foregroundServiceNotificationId: 888,
    ),
    iosConfiguration: IosConfiguration(
      autoStart: false,
      onForeground: onBackgroundServiceStart,
      onBackground: onIosBackground,
    ),
  );
}

@pragma('vm:entry-point')
Future<bool> onIosBackground(ServiceInstance service) async {
  WidgetsFlutterBinding.ensureInitialized();
  DartPluginRegistrant.ensureInitialized();
  return true;
}

@pragma('vm:entry-point')
void onBackgroundServiceStart(ServiceInstance service) async {
  DartPluginRegistrant.ensureInitialized();

  if (service is AndroidServiceInstance) {
    service.on('setAsForeground').listen((_) =>
        service.setAsForegroundService());
    service.on('setAsBackground').listen((_) =>
        service.setAsBackgroundService());
  }

  service.on('stopService').listen((_) => service.stopSelf());

  // Periyodik işlem
  Timer.periodic(const Duration(seconds: 30), (timer) async {
    if (service is AndroidServiceInstance &&
        !await service.isForegroundService()) {
      timer.cancel();
      return;
    }

    // Konum güncelle
    final pos = await Geolocator.getCurrentPosition();
    service.invoke('locationUpdate', {
      'lat': pos.latitude,
      'lng': pos.longitude,
      'timestamp': DateTime.now().toIso8601String(),
    });

    // Bildirimi güncelle
    service.setForegroundNotificationInfo(
      title: 'Takip Aktif',
      content: '${pos.latitude.toStringAsFixed(4)}, ${pos.longitude.toStringAsFixed(4)}',
    );
  });
}

// UI'dan servisi başlatma/durdurma
FloatingActionButton(
  onPressed: () async {
    final service = FlutterBackgroundService();
    if (await service.isRunning()) {
      service.invoke('stopService');
    } else {
      service.startService();
    }
  },
  child: const Icon(Icons.location_on),
)

Arka plan görevleri için doğru aracı seçin: kısa ve periyodik görevler için WorkManager, CPU-yoğun hesaplamalar için Isolate, sürekli çalışan servisler için flutter_background_service. Her üçü de pil optimizasyonuna dikkat eder; gereksiz arka plan işlemlerinden kaçının.