Flutter background service get user location failed

771 views Asked by At

My Flutter app requires fetching the user's current location after a periodic time even app is in the background or clear from recent. To run app in background mode I am using flutter_background_service. I have implemented the example and works fine to show the current time in the notification.

When I am trying to call _getLocation(location) function at onStart it is showing error Failed to handle method call.

void onStart(ServiceInstance service) async {}

If I call _getLocation(location) function from UI, it is working fine.

Any help will be highly appreciable. Thanks

Future<LocationData> _getLocation(Location location) async {
  final locationResult = await location.getLocation();
    LocationData? _location = locationResult;
    print('location print - ${_location}');
    return _location; 
}

my code

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await initializeService();
  runApp(const MyApp());
}

Future<void> initializeService() async {
  final service = FlutterBackgroundService();

  /// OPTIONAL, using custom notification channel id
  const AndroidNotificationChannel channel = AndroidNotificationChannel(
    'my_foreground', // id
    'MY FOREGROUND SERVICE', // title
    description: 'This channel is used for important notifications.', // description
    importance: Importance.low, // importance must be at low or higher level
  );

  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
  FlutterLocalNotificationsPlugin();

  if (Platform.isIOS || Platform.isAndroid) {
    await flutterLocalNotificationsPlugin.initialize(
      const InitializationSettings(
        iOS: DarwinInitializationSettings(),
        android: AndroidInitializationSettings('ic_bg_service_small'),
      ),
    );
  }


  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
      AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(channel);

  await service.configure(
    androidConfiguration: AndroidConfiguration(
      // this will be executed when app is in foreground or background in separated isolate
      onStart: onStart,

      // auto start service
      autoStart: true,
      isForegroundMode: true,

      notificationChannelId: 'my_foreground',
      initialNotificationTitle: 'AWESOME SERVICE',
      initialNotificationContent: 'Initializing',
      foregroundServiceNotificationId: 888,
    ),
    iosConfiguration: IosConfiguration(
      // auto start service
      autoStart: true,

      // this will be executed when app is in foreground in separated isolate
      onForeground: onStart,

      // you have to enable background fetch capability on xcode project
      onBackground: onIosBackground,
    ),
  );

  service.startService();
}

// to ensure this is executed
// run app from xcode, then from xcode menu, select Simulate Background Fetch

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

  SharedPreferences preferences = await SharedPreferences.getInstance();
  await preferences.reload();
  final log = preferences.getStringList('log') ?? <String>[];
  log.add(DateTime.now().toIso8601String());
  await preferences.setStringList('log', log);

  return true;
}

@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
  // Only available for flutter 3.0.0 and later
  DartPluginRegistrant.ensureInitialized();

  // For flutter prior to version 3.0.0
  // We have to register the plugin manually

  Location location = Location();
  LocationData? _location;

  //_location = await _getLocation(location);

  //print('location = ${_location}');

  SharedPreferences preferences = await SharedPreferences.getInstance();
  await preferences.setString("hello", "world");

  /// OPTIONAL when use custom notification
  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
  FlutterLocalNotificationsPlugin();

  if (service is AndroidServiceInstance) {
    service.on('setAsForeground').listen((event) {
      service.setAsForegroundService();
    });

    service.on('setAsBackground').listen((event) {
      service.setAsBackgroundService();
    });
  }

  service.on('stopService').listen((event) {
    service.stopSelf();
  });

  // bring to foreground
  Timer.periodic(const Duration(seconds: 3), (timer) async {
    //_location = await _getLocation(location);
    if (service is AndroidServiceInstance) {
      if (await service.isForegroundService()) {
        /// OPTIONAL for use custom notification
        /// the notification id must be equals with AndroidConfiguration when you call configure() method.
        flutterLocalNotificationsPlugin.show(
          888,
          'COOL SERVICE',
          'Awesome ${DateTime.now()}',
          const NotificationDetails(
            android: AndroidNotificationDetails(
              'my_foreground',
              'MY FOREGROUND SERVICE',
              icon: 'ic_bg_service_small',
              ongoing: true,
            ),
          ),
        );

        // if you don't using custom notification, uncomment this
        service.setForegroundNotificationInfo(
          title: "My App Service",
          content: "${DateTime.now()}",
        );
      }
    }

    /// you can see this log in logcat
    print('FLUTTER BACKGROUND SERVICE: ${DateTime.now()}');

    _location = await _getLocation(location);

    //print('location = ${_location}');

    // test using external plugin
    final deviceInfo = DeviceInfoPlugin();
    String? device;
    if (Platform.isAndroid) {
      final androidInfo = await deviceInfo.androidInfo;
      device = androidInfo.model;
    }

    if (Platform.isIOS) {
      final iosInfo = await deviceInfo.iosInfo;
      device = iosInfo.model;
    }

    service.invoke(
      'update',
      {
        //"current_date": DateTime.now().toIso8601String(),
        "current_date": DateTime.now().toString(),
        "device": device,
        "location": _location
      },
    );
  });
}

Error log is

E/MethodChannel#lyokone/location(28616): Failed to handle method call
E/MethodChannel#lyokone/location(28616): java.lang.NullPointerException: Attempt to write to field 'io.flutter.plugin.common.MethodChannel$Result com.lyokone.location.FlutterLocation.getLocationResult' on a null object reference
E/MethodChannel#lyokone/location(28616):    at com.lyokone.location.MethodCallHandlerImpl.onGetLocation(MethodCallHandlerImpl.java:117)
E/MethodChannel#lyokone/location(28616):    at com.lyokone.location.MethodCallHandlerImpl.onMethodCall(MethodCallHandlerImpl.java:43)
E/MethodChannel#lyokone/location(28616):    at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258)
E/MethodChannel#lyokone/location(28616):    at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
E/MethodChannel#lyokone/location(28616):    at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322)
E/MethodChannel#lyokone/location(28616):    at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/MethodChannel#lyokone/location(28616):    at android.os.Handler.handleCallback(Handler.java:938)
E/MethodChannel#lyokone/location(28616):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/MethodChannel#lyokone/location(28616):    at android.os.Looper.loop(Looper.java:263)
E/MethodChannel#lyokone/location(28616):    at android.app.ActivityThread.main(ActivityThread.java:8299)
E/MethodChannel#lyokone/location(28616):    at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#lyokone/location(28616):    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
E/MethodChannel#lyokone/location(28616):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)
E/flutter (28616): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(error, Attempt to write to field 'io.flutter.plugin.common.MethodChannel$Result com.lyokone.location.FlutterLocation.getLocationResult' on a null object reference, null, java.lang.NullPointerException: Attempt to write to field 'io.flutter.plugin.common.MethodChannel$Result com.lyokone.location.FlutterLocation.getLocationResult' on a null object reference
E/flutter (28616):  at com.lyokone.location.MethodCallHandlerImpl.onGetLocation(MethodCallHandlerImpl.java:117)
E/flutter (28616):  at com.lyokone.location.MethodCallHandlerImpl.onMethodCall(MethodCallHandlerImpl.java:43)
E/flutter (28616):  at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258)
E/flutter (28616):  at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
E/flutter (28616):  at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322)
E/flutter (28616):  at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/flutter (28616):  at android.os.Handler.handleCallback(Handler.java:938)
E/flutter (28616):  at android.os.Handler.dispatchMessage(Handler.java:99)
E/flutter (28616):  at android.os.Looper.loop(Looper.java:263)
E/flutter (28616):  at android.app.ActivityThread.main(ActivityThread.java:8299)
E/flutter (28616):  at java.lang.reflect.Method.invoke(Native Method)
E/flutter (28616):  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
E/flutter (28616):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)
E/flutter (28616): )
E/flutter (28616): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653:7)
E/flutter (28616): #1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:315:18)
E/flutter (28616): <asynchronous suspension>
E/flutter (28616): #2      MethodChannel.invokeMapMethod (package:flutter/src/services/platform_channel.dart:518:43)
E/flutter (28616): <asynchronous suspension>
E/flutter (28616): #3      MethodChannelLocation.getLocation (package:location_platform_interface/src/method_channel_location.dart:83:9)
E/flutter (28616): <asynchronous suspension>
E/flutter (28616): #4      _getLocation (package:track_my_people/main.dart:269:26)
E/flutter (28616): <asynchronous suspension>
E/flutter (28616): #5      onStart (package:track_my_people/main.dart:140:15)
E/flutter (28616): <asynchronous suspension>
E/flutter (28616): 
0

There are 0 answers