ekasetiawans / flutter_background_service

269 stars 191 forks source link

Bug: Application Crash for SDK 34 #484

Open book-g opened 1 month ago

book-g commented 1 month ago

Application Crash.

  1. Compile and Target SDK as 34
  2. Implemented the code as said in document but the application is not working, app crash.
  3. Please given proper code.
  4. flutter_background_service: ^5.0.5

Exception

permission

java.lang.RuntimeException: Unable to create service id.flutter.flutter_background_service.BackgroundService: android.app.MissingForegroundServiceTypeException: Starting FGS without a type  callerApp=ProcessRecord{6e66ea0 6565:com.fieldlytics.framex/u0a274} targetSDK=34
E/AndroidRuntime( 6565):    at android.app.ActivityThread.handleCreateService(ActivityThread.java:4773)
E/AndroidRuntime( 6565):    at android.app.ActivityThread.-$$Nest$mhandleCreateService(Unknown Source:0)
E/AndroidRuntime( 6565):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2335)
E/AndroidRuntime( 6565):    at android.os.Handler.dispatchMessage(Handler.java:106)
E/AndroidRuntime( 6565):    at android.os.Looper.loopOnce(Looper.java:232)
E/AndroidRuntime( 6565):    at android.os.Looper.loop(Looper.java:334)
E/AndroidRuntime( 6565):    at android.app.ActivityThread.main(ActivityThread.java:8293)
E/AndroidRuntime( 6565):    at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime( 6565):    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
E/AndroidRuntime( 6565):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1062)
E/AndroidRuntime( 6565): Caused by: android.app.MissingForegroundServiceTypeException: Starting FGS without a type  callerApp=ProcessRecord{6e66ea0 6565:com.fieldlytics.framex/u0a274} targetSDK=34
E/AndroidRuntime( 6565):    at android.app.MissingForegroundServiceTypeException$1.createFromParcel(MissingForegroundServiceTypeException.java:53)
E/AndroidRuntime( 6565):    at android.app.MissingForegroundServiceTypeException$1.createFromParcel(MissingForegroundServiceTypeException.java:49)
E/AndroidRuntime( 6565):    at android.os.Parcel.readParcelableInternal(Parcel.java:4870)
E/AndroidRuntime( 6565):    at android.os.Parcel.readParcelable(Parcel.java:4852)
E/AndroidRuntime( 6565):    at android.os.Parcel.createExceptionOrNull(Parcel.java:3052)
E/AndroidRuntime( 6565):    at android.os.Parcel.createException(Parcel.java:3041)
E/AndroidRuntime( 6565):    at android.os.Parcel.readException(Parcel.java:3024)
E/AndroidRuntime( 6565):    at android.os.Parcel.readException(Parcel.java:2966)
E/AndroidRuntime( 6565):    at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:6966)
E/AndroidRuntime( 6565):    at android.app.Service.startForeground(Service.java:862)
E/AndroidRuntime( 6565):    at androidx.core.app.ServiceCompat$Api34Impl.startForeground(ServiceCompat.java:238)
E/AndroidRuntime( 6565):    at androidx.core.app.ServiceCompat.startForeground(ServiceCompat.java:172)
E/AndroidRuntime( 6565):    at id.flutter.flutter_background_service.BackgroundService.updateNotificationInfo(BackgroundService.java:172)
E/AndroidRuntime( 6565):    at id.flutter.flutter_background_service.BackgroundService.onCreate(BackgroundService.java:105)
E/AndroidRuntime( 6565):    at android.app.ActivityThread.handleCreateService(ActivityThread.java:4760)
E/AndroidRuntime( 6565):    ... 9 more
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:frame/conts/string_const.dart';
import 'package:frame/database_helper/exceptiontable_impl.dart';
import 'package:frame/database_helper/user_impl.dart';
import 'package:frame/models/exception_model/exception_model.dart';
import 'package:frame/models/user_model.dart';
import 'package:frame/providers/pjp_plan_provider.dart';
import 'package:frame/providers/store_provider.dart';
import 'package:frame/providers/sync_provider.dart';
import 'package:frame/schedular/periodic.dart';
import 'package:frame/services/activity_log_in_db.dart';
import 'package:frame/services/database_helper.dart';
import 'package:frame/utils/appbar_util.dart';
import 'package:frame/utils/apputilityfunction.dart';
import 'package:frame/utils/endpoint.dart';
import 'package:intl/intl.dart';

///The provided code is related to managing background services and notifications in a Flutter application. Here's a summary of the code:
//
// 1. **Service Initialization**:
//    - The `initializeService` function is responsible for initializing background services. It configures background service settings for both iOS and Android platforms.
//    - It sets up a notification channel using the `FlutterLocalNotificationsPlugin` for Android.
//    - The service is configured to start automatically when the app is foregrounded or in the background.
//
// 2. **`onStart` Function**:
//    - The `onStart` function is the entry point for the background service and is executed when the service is started.
//    - It listens to different events such as `'sync'`, `'upload'`, `'help'`, `'close_upload'`, `'download_target'`, `'call_get'`, `'alarm_trig'`, `'b_form_init'`, and `'stop'` using `service.on()`.
//    - It performs various actions based on these events, including showing notifications, running timers, and executing specific tasks.
//
// 3. **Notifications**:
//    - The `showNotification` function is used to display notifications using the `FlutterLocalNotificationsPlugin`.
//    - It takes parameters such as `ids`, `title`, and `content` to customize the notification content.
//
// 4. **Timer Usage**:
//    - Timers are used in different parts of the code to schedule periodic tasks. For example, there's a timer that runs the upload process every 15 minutes.
//
// 5. **Service Configuration**:
//    - The service is configured to auto-start and run in the foreground mode, which allows it to continue running even when the app is in the background.
//
// 6. **Error Handling**:
//    - There are try-catch blocks in place to handle exceptions that might occur during service initialization or execution.
//
// 7. **iOS-specific Configuration**:
//    - Special configurations are made for iOS, such as initializing `FlutterLocalNotificationsPlugin` with iOS settings.
//
// Overall, this code sets up a background service that can perform various tasks based on events triggered by the application. It also handles notifications to keep users informed about ongoing background processes. The service can be started, stopped, and configured to run specific tasks at defined intervals.

const id = "framex_foreground", name = "FrameX", icon = "ic_frame_logo";

SyncProvider syncProvider = SyncProvider();
Future<void> initializeService() async {
  // Create a new service instance
  try {
    final service = FlutterBackgroundService();

    // Create a new Android notification channel
    AndroidNotificationChannel channel = const AndroidNotificationChannel(
      id,
      name,
      description: "Notification",
      importance: Importance.high,
    );

    // Create a new FlutterLocalNotificationsPlugin instance
    final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
        FlutterLocalNotificationsPlugin();

    // Check if the platform is iOS
    if (Platform.isIOS) {
      // Initialize the FlutterLocalNotificationsPlugin with iOS settings
      await flutterLocalNotificationsPlugin.initialize(
          const InitializationSettings(iOS: DarwinInitializationSettings()));
    }

    // Create a new AndroidFlutterLocalNotificationsPlugin instance
    await flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.createNotificationChannel(channel);

    // Configure the service with the iOS and Android settings
    await service.configure(
        iosConfiguration: IosConfiguration(
            // Enable auto-start
            autoStart: true,
            // Start the service when the app is foreground
            onForeground: onStart,
            // Start the service when the app is background
            onBackground: onIosBackground),
        androidConfiguration: AndroidConfiguration(
            // Enable auto-start
            autoStart: true,
            // Start the service when the app is foreground
            onStart: onStart,
            // Enable foreground mode
            isForegroundMode: true,
            // Set the notification channel ID
            notificationChannelId: id,
            // Set the initial notification title
            initialNotificationTitle: name,
            // Set the initial notification content
            initialNotificationContent: 'Framex is running in background.',
            // Set the foreground service notification ID
            foregroundServiceNotificationId: 1));

    // Start the service
    service.startService();
  } catch (e) {
    String entryDate = Endpoints().dateFor();
    await ExceptionTableImpl.insertException(ExceptionModel(
        storeId: "",
        entryDate: "$entryDate",
        process: "initializeService()",
        exception: "${e}",
        filename: "background_process.dart",
        lineno: "117"));
  }
}

Timer? start;
@pragma('vm:entry-point')
onStart(ServiceInstance service) async {
  try {
    String entryDate = Endpoints().dateFor();

    DartPluginRegistrant.ensureInitialized();

// Create a new instance of the FlutterLocalNotificationsPlugin class
    FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
        FlutterLocalNotificationsPlugin();

// Try to cancel the start command
    try {
      if (start != null) {
        start!.cancel();
      }
    } catch (e) {
      await ExceptionTableImpl.insertException(ExceptionModel(
          storeId: "",
          entryDate: "$entryDate",
          process: "onStart()",
          exception: "${e}",
          filename: "background_process.dart",
          lineno: "145"));
    }

// Try to stop the FlutterBackgroundService
    try {
      FlutterBackgroundService().invoke("stop");
    } catch (e) {
      await ExceptionTableImpl.insertException(ExceptionModel(
          storeId: "",
          entryDate: "$entryDate",
          process: "FlutterBackgroundService().invoke(stop);",
          exception: "${e}",
          filename: "background_process.dart",
          lineno: "158"));
    }
    service.on('sync').listen((event) {
      // Prints a message to the console when the service is started in the foreground
      print("Started Foreground ==>> ${service.runtimeType} sync");
    });

    service.on(BS.GUIDE).listen((event) async {
      // Prints a message to the console when the service is started
      print("Started Foreground ==>> ${service.runtimeType} ${BS.GUIDE}");
    });

    service.on(BS.UPLOAD).listen((event) async {
      //Print the runtime type and upload event

      print("Started Foreground ==>> ${service.runtimeType} ${BS.UPLOAD}");
      //Show a notification with the title and content

      try {
        showNotification(
            ids: 2,
            title: 'FrameX - Upload',
            content: 'Syncing process started');
      } catch (e) {
        await ExceptionTableImpl.insertException(ExceptionModel(
            storeId: "",
            entryDate: "$entryDate",
            process: " service.on(BS.UPLOAD).listen((event)",
            exception: "${e}",
            filename: "background_process.dart",
            lineno: "207"));
      }
      await DatabaseHelper.instance.database;
      await syncProvider.uploadAll();
    });

    service.on(BS.HELP).listen((event) async {
      //Print a message to the console when the service starts
      print("Started Foreground ==>> ${service.runtimeType} ${BS.HELP}");
    });

    service.on(BS.CLOSE_UPLOAD).listen((event) async {
      // Prints a message to the console when the service is started
      print(
          "Started Foreground ==>> ${service.runtimeType} ${BS.CLOSE_UPLOAD}");
    });

    service.on(BS.DOWNLOAD_TARGET).listen((event) async {
      // Print the runtime type and download target
      print(
          "Started Foreground ==>> ${service.runtimeType} ${BS.DOWNLOAD_TARGET}");

      // PjpProvider data= PjpProvider();
      // data.getCallPlanSetup();
    });

    service.on(BS.CALL_GET).listen((event) async {
      print("Started Foreground ==>> ${service.runtimeType} ${BS.CALL_GET}");

      try {
        PjpProvider pjpProvider = PjpProvider();

        // Get the user from the database
        UserModel user = await UserImpl.getUser();
        // Get the PJP plan and call plan setup from the database
        await pjpProvider.getPjpPlan(user);
        await pjpProvider.getCallPlanSetup();
      } catch (e) {
        print("Error $e ====MLM= BS.CALL_GET===${BS.CALL_GET}");
      }
    });

    service.on(BS.TIMER_SCH).listen((event) async {
      await Periodic.perform(execute: () async {
        DateTime time = Endpoints().datetimenow();

        int hour = time.hour, min = time.minute;
        print(
            "=====CAlll AlarmTrigger how many minute to trigger=  --- $hour $min");

        if (hour == 0 && min == 0) {
          UserModel? userModel = await UserImpl.getUser();

          try {
            var ist = await AppUtilityFunction.isConnectingToInternet();
            if (ist) {
              await ActivityLogInDb.saveInActivityLog(
                  '${userModel!.cAccCode}', "Wifi or Mobile Data is Connected");
            } else {
              await ActivityLogInDb.saveInActivityLog('${userModel!.cAccCode}',
                  "Please Check Network,No Wifi or Mobile Data is Connected");
            }
          } catch (e) {}

          try {
            await DatabaseHelper.dropBasedOnAlarmTrig();
            // Get the user model from the database
            userModel!.todayAttendance = "";
            await UserImpl.updateUser(userModel);
            // Save the user model in the activity log
            await ActivityLogInDb.saveInActivityLog(
                '${userModel.cAccCode}', "Sync processes at 12 AM daily Start");
          } catch (e) {
            UserModel? userModel = await UserImpl.getUser();
            await ActivityLogInDb.saveInActivityLog('${userModel!.cAccCode}',
                "$e = Sync processes at 12 AM daily Start");
          }

          await alramtri(userModel);

          await initializeService();

          // try {
          //   await ActivityLogSend.sendLogs();
          //   //await ActivityLogSend.sendLogs();
          // } catch (e) {
          //   UserModel? userModel = await UserImpl.getUser();
          //   await ActivityLogInDb.saveInActivityLog(
          //       '${userModel!.cAccCode}', "$e = Sync processes at 12 AM daily Start");
          // }
        }
      });
    });

    service.on(BS.ALARM_TRIG).listen((event) async {
      print("Started Foreground ==>> ${service.runtimeType} ${BS.ALARM_TRIG}");

      // print("Started Foreground ==>> ${service.runtimeType} ${BS.ALARM_TRIG}");
      await initializeService();

      // try{
      PjpProvider pjpProvider = PjpProvider();

      // await DatabaseHelper.instance.database;

      // Get the user from the database
      await DatabaseHelper.instance.database;

      // Get the user from the database
      var user = await UserImpl.getUser();
      if (user != null) {
        // Get the PJP plan and call plan setup from the database
        await pjpProvider.getPjpPlan(user);
        await pjpProvider.getCallPlanSetup();
      }

      try {
        // Upload all the data to the server
        await syncProvider.uploadAll();
      } catch (e) {}

      try {
        //await ActivityLogSend.sendLogs();
        //await ActivityLogSend.sendLogs();
        await sendMobileLogs();
      } catch (e) {
        UserModel? userModel = await UserImpl.getUser();
        await ActivityLogInDb.saveInActivityLog('${userModel!.cAccCode}',
            "$e = Sync processes at 12 AM daily Start");
      }

      //  }catch(e){
      // print("Error $e ====MLM= BS.CALL_GET===${BS.CALL_GET}");

      // }
      await SystemNavigator.pop();
      exit(0);
    });

    service.on('b_form_init').listen((event) async {
      print("Started Foreground ==>> ${service.runtimeType} b_form_init");

      // try{
      StoreProvider storeProvider = StoreProvider();

      storeProvider.multipleCategory();
      // storeProvider.multipleCategory();
      //UserModel user = await UserImpl.getUser();

      //  }catch(e){
      // print("Error $e ====MLM= BS.CALL_GET===${BS.CALL_GET}");

      // }
    });

    service.on('stop').listen((event) async {
      // Stop the service
      await service.stopSelf();
      try {
        // Cancel the start command
        start!.cancel();
      } catch (e) {}
      // Stop the service
      await service.stopSelf();
    });

    service.on('upload_activity_log').listen((event) async {
      // Get the current time
      DateTime time = Endpoints().datetimenow();

      // If the time is between 8am and 5pm, send the logs
      if (time.hour == 8 ||
          time.hour == 12 ||
          time.hour == 13 ||
          time.hour == 1) {
        try {
          // Send the logs
          //await ActivityLogSend.sendLogs();
          await sendMobileLogs();
        } catch (e) {}
      }

      // Periodically send the logs
      //Timer.periodic(Duration(seconds: 1), (timer) async {});
    });

    print("N===MLM= BS.CALL_GET===${BS.CALL_GET}");
  } catch (e) {
    String entryDate = Endpoints().dateFor();
    await ExceptionTableImpl.insertException(ExceptionModel(
        storeId: "",
        entryDate: "$entryDate",
        process: "onStart(ServiceInstance service)",
        exception: "${e}",
        filename: "background_process.dart",
        lineno: "398"));
  }
}

// This function is used to run when the iOS background event is triggered
@pragma('vm:entry-point')
FutureOr<bool> onIosBackground(ServiceInstance service) async {
  // Ensure that the WidgetsFlutterBinding and DartPluginRegistrant are initialized
  WidgetsFlutterBinding.ensureInitialized();
  DartPluginRegistrant.ensureInitialized();

  // Return true to indicate that the background event was handled
  return true;
}

//This function shows a notification with the given parameters
showNotification({ids, title = "Title", content = "Content"}) async {
  String entryDate = Endpoints().dateFor();

  try {
    //Create a new instance of the FlutterLocalNotificationsPlugin class
    FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
        FlutterLocalNotificationsPlugin();
    //Call the show method on the plugin instance, passing in the given parameters
    flutterLocalNotificationsPlugin.show(
      ids,
      title,
      content,
      //Create a new NotificationDetails object with the given parameters
      const NotificationDetails(
        android: AndroidNotificationDetails(
          id,
          name,
          icon: 'ic_frame_logo',

          //ongoing: true,
        ),
      ),
    );
  } catch (e) {
    await ExceptionTableImpl.insertException(ExceptionModel(
        storeId: "",
        entryDate: "$showNotification",
        process: "showNotification()",
        exception: "${e}",
        filename: "background_process.dart",
        lineno: "444"));
  }
}

alramtri(user) async {
  String entryDate = Endpoints().dateFor();
  try {
    print("Started Foreground ==>>  ${BS.ALARM_TRIG}");

    PjpProvider pjpProvider = PjpProvider();

    await DatabaseHelper.instance.database;

    if (user != null) {

      await pjpProvider.getPjpPlan(user);
      await pjpProvider.getCallPlanSetup();

    }

    try {
      await syncProvider.uploadAll();
    } catch (e) {
      await ExceptionTableImpl.insertException(ExceptionModel(
          storeId: "",
          entryDate: "$entryDate",
          process: "alramtri() - uploadAll()",
          exception: "${e}",
          filename: "background_process.dart",
          lineno: "473"));
    }

    await ActivityLogInDb.saveInActivityLog(
        '${user!.cAccCode}', "Syncing processes ongoing");

    await SystemNavigator.pop();
    exit(0);
  } catch (e) {
    await ExceptionTableImpl.insertException(ExceptionModel(
        storeId: "",
        entryDate: "$entryDate",
        process: "alramtri()",
        exception: "${e}",
        filename: "background_process.dart",
        lineno: "487"));
  }
}
zamargab commented 1 month ago

I am having same issue

matgallacher commented 5 days ago

Did you try this additional config setting the foreground modes for the AndroidSettings and adding the additional permissions?

https://github.com/ekasetiawans/flutter_background_service?tab=readme-ov-file#configuration-required-for-foreground-services-on-android-14-sdk-34