transistorsoft / flutter_background_fetch

Periodic callbacks in the background for both IOS and Android. Includes Android Headless mechanism
MIT License
570 stars 166 forks source link

background fetch not running when app is closed #382

Open zsrour1991 opened 2 hours ago

zsrour1991 commented 2 hours ago

import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:ess_application/appservices_lib.dart'; import 'package:ess_core/esscore_lib.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:get_it/get_it.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:background_fetch/background_fetch.dart';

class BackGroundHelper { late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin; late Timer _timer;

BackGroundHelper() { initializeNotifications(); initBackgroundFetch(); //registration(); startTimer(); // Start the timer here } static late NotificationService notificationService = locator(); // Declare NotificationService

static GetIt sl = GetIt.instance;

Future initializeNotifications() async { print("initializeNotifications"); flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

const AndroidInitializationSettings initializationSettingsAndroid =
    AndroidInitializationSettings('@mipmap/ic_launcher');

const InitializationSettings initializationSettings =
    InitializationSettings(
  android: initializationSettingsAndroid,
  iOS: DarwinInitializationSettings(),
);

await flutterLocalNotificationsPlugin.initialize(initializationSettings,
    onDidReceiveNotificationResponse: (NotificationResponse response) {
  print("Notification tapped: ${response.payload}");
});

// Create notification channel
_createNotificationChannel();

// For iOS, request permission
if (Platform.isIOS) {
  final permissionGranted = await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
          IOSFlutterLocalNotificationsPlugin>()
      ?.requestPermissions(
        alert: true,
        badge: true,
        sound: true,
      );
  print('Permission granted: $permissionGranted');
}

}

Future _createNotificationChannel() async { const AndroidNotificationChannel channel = AndroidNotificationChannel( 'your_channel_id', // Unique ID for the channel 'your_channel_name', // User-visible name for the channel description: 'your_channel_description', // Description for the channel importance: Importance.max, // Importance level for notifications playSound: true, // Play sound for notifications ); await requestPermissions(); flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channel); }

Future showNotification() async { print("Showing notification..."); var androidPlatformChannelSpecifics = AndroidNotificationDetails( 'your_channel_id', // Ensure this matches the channel ID used in _createNotificationChannel 'your_channel_name', channelDescription: 'your_channel_description', importance: Importance.max, priority: Priority.high, playSound: true, // Ensure this is set if you want sound ); var platformChannelSpecifics = NotificationDetails( android: androidPlatformChannelSpecifics, iOS: DarwinNotificationDetails(), );

try {
  print("fetch notification");
  SharedPreferences sp = await SharedPreferences.getInstance();

  if (sp.getInt('companyId') != null) {
    print("fetch notification");
    print(sp.getInt('companyId'));
    await notificationService.fetch().then((value) async {
      print("Fetching notifications");
      print(notificationService.state.notificationsUnseen.length);
      if (notificationService.state.notificationsUnseen.isNotEmpty) {
        print("----------------------");
        // if(sp.getInt("notificationId")!=notificationService.state.notificationsUnseen[0].id!){
        sp.setInt("notificationId",
            notificationService.state.notificationsUnseen[0].id!);
        await flutterLocalNotificationsPlugin.show(
          notificationService.state.notificationsUnseen[0].id!,
          "${changeTime(notificationService.state.notificationsUnseen[0].dateCreated!, 6, true)} ${notificationService.state.notificationsUnseen[0].companyName!}",
          notificationService.state.notificationsUnseen[0].text!,
          const NotificationDetails(
            android: AndroidNotificationDetails(
                'your_channel_id', 'your_channel_name',
                channelDescription: 'your_channel_description',
                importance: Importance.max,
                icon: '@mipmap/ic_launcher'),
            iOS: DarwinNotificationDetails(),
          ),
          payload: jsonEncode({
            'id': notificationService.state.notificationsUnseen[0].id,
            'companyName': notificationService
                .state.notificationsUnseen[0].companyName,
          }),
        ); //}
      }
    });
  }

  print("Notification displayed successfully.");
} catch (e) {
  print("Error displaying notification: $e");
}

}

static Future requestPermissions() async { if (Platform.isAndroid) { var status = await Permission.notification.status; if (!status.isGranted) { await Permission.notification.request(); } } else if (Platform.isIOS) { var status = await Permission.notification.isGranted; if (!status) { await Permission.notification.request(); } } }

@pragma('vm:entry-point') void backgroundFetchHeadlessTask(HeadlessTask task) async { print("Headless Task Triggered: ${task.taskId}"); try { await BackGroundHelper().showNotification(); } catch (e) { print("Error in headless task: $e"); } BackgroundFetch.finish(task.taskId); }

void initBackgroundFetch() { print("initBackgroundFetch"); BackgroundFetch.configure( BackgroundFetchConfig( minimumFetchInterval: 15, stopOnTerminate: false, enableHeadless: true, startOnBoot: true, ), (String taskId) async { print("[BackgroundFetch] Event received: $taskId"); await showNotification(); BackgroundFetch.finish(taskId); }, ).then((int status) { print("[BackgroundFetch] configure success: $status"); }).catchError((e) { print("[BackgroundFetch] configure ERROR: $e"); }); }

void startTimer() { _timer = Timer.periodic(Duration(seconds: 15), (timer) { showNotification(); }); }

void stopTimer() { _timer.cancel(); }

void ini() { BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask); } }

christocracy commented 2 hours ago

The issue template is required, not optional;

Your Environment

To Reproduce Steps to reproduce the behavior:

Debug logs

Additional context Add any other context about the problem here.