flutter_background_service icon indicating copy to clipboard operation
flutter_background_service copied to clipboard

how to work with other plugin?

Open xiaochonzi opened this issue 2 years ago • 17 comments

i am write an app that can backgroud location tracking and use flutter_bmflocation=3.2.1. it is run fine,when app is first start and ervery thing work fine. but when i killed the app, it don't track,and catch the third plugin MissingPluginException.

E/flutter (23674): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method flutter_bmflocation/setOptions on channel flutter_bmflocation)
E/flutter (23674): #0      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:294:7)
E/flutter (23674): <asynchronous suspension>
E/flutter (23674): #1      BMFLocationOptionsDispatcher.setLocationOptions (package:flutter_bmflocation/src/private/dispatcher/bdmap_location_options_dispather.dart:15:18)
E/flutter (23674): <asynchronous suspension>
E/flutter (23674): 

and my onStart code is like this:

@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
  WidgetsFlutterBinding.ensureInitialized();
  DartPluginRegistrant.ensureInitialized();
  final LocationFlutterPlugin locPlugin = LocationFlutterPlugin();
  SpUtils.init();
  if (service is AndroidServiceInstance) {
 
    service.on('setAsForeground').listen((event) {
      service.setAsForegroundService();
    });
 
    service.on('setAsBackground').listen((event) {
      service.setAsBackgroundService();
    });
  }
  service.on('stopService').listen((event) {
    locPlugin.stopLocation();
    service.stopSelf();
  });
  // location track callback ,return location info
  locPlugin.seriesLocationCallback(callback: (data){
    service.invoke("updateLocation", {"location":data.getMap()});
  });
  Timer.periodic(const Duration(seconds: 5), (timer) async {
 
    if (service is AndroidServiceInstance) {
      if (await service.isForegroundService()) {
        service.setForegroundNotificationInfo(
          title: "My App Service",
          content: "Updated at ${DateTime.now()}",
        );
      }
    }
    service.invoke('update', {"current_date": DateTime.now().toIso8601String(),},);
    bool? isAgree = SpUtils.getBaiduAgree(); 
    bool isPermission = await PermissionUtils.checkPermissionStatus(Permission.location);
    print("isAgree ${isAgree} isPermission ${isPermission}");
    if (isAgree && isPermission){
      BaiduLocationAndroidOption androidOption = BaiduPlugin.initAndroidOptions();
      BaiduLocationIOSOption iosOption = BaiduPlugin.initIOSOptions();
      print('location settings:${iosOption.getMap()}');
      locPlugin.prepareLoc(androidOption.getMap(), iosOption.getMap());
      print('start location track');
      locPlugin.startLocation();
    }
  });
}

xiaochonzi avatar Oct 03 '22 08:10 xiaochonzi

There are so many kinds of flutter plugin that requires an Activity object for registering their platform channels. Since the Service is not an Activity, there is impossible to use any flutter plugin that requires an Activity. You have to look into the plugin native code, and if you found that platform channel is registered in onActivityAttached, or any method handler requires an activity from it, then it means we cannot use that plugin in a Service.

ekasetiawans avatar Oct 03 '22 11:10 ekasetiawans

@ekasetiawans At the beginning, I thought the same as you, so I went to check the source code, but didn't find any need for Activity. i have no idea, so i came here for help.

xiaochonzi avatar Oct 03 '22 11:10 xiaochonzi

@xiaochonzi have you tried with other flutter plugin, for example shared_preferences? if you can use any method from it, then i think the problem is in the plugin you use.

ekasetiawans avatar Oct 03 '22 12:10 ekasetiawans

@ekasetiawans yes ,i have runed the example which you write. and ervery thing run fine.

xiaochonzi avatar Oct 03 '22 12:10 xiaochonzi

@ekasetiawans I've solved the problem, and sure enough it was a problem with a 3rd party plugin that used the static keyword when declaring the MethodChannel in android java code. But what is puzzling is how static affects this bug.

xiaochonzi avatar Oct 04 '22 04:10 xiaochonzi

@ekasetiawans I've solved the problem, and sure enough it was a problem with a 3rd party plugin that used the static keyword when declaring the MethodChannel in android java code. But what is puzzling is how static affects this bug.

Could you elaborate more?

ekasetiawans avatar Oct 04 '22 12:10 ekasetiawans

I use the geolocator package and it works fine with this lib

Wackymax avatar Oct 10 '22 08:10 Wackymax

I use the geolocator package and it works fine with this lib

How did you use the geolocator package can you share your source code?

imsifat1 avatar Oct 27 '22 10:10 imsifat1

I use the geolocator package and it works fine with this lib

Yes, this plugin is working fine.

Process:

  1. Add the plugin geolocator: {{latestversion}}
  2. follow my code to add geo location with onStart()
Future<Position> _determinePosition() async {
  bool serviceEnabled;
  LocationPermission permission;

  // Test if location services are enabled.
  serviceEnabled = await Geolocator.isLocationServiceEnabled();
  if (!serviceEnabled) {
    // Location services are not enabled don't continue
    // accessing the position and request users of the
    // App to enable the location services.
    return Future.error('Location services are disabled.');
  }

  permission = await Geolocator.checkPermission();
  if (permission == LocationPermission.denied) {
    permission = await Geolocator.requestPermission();
    if (permission == LocationPermission.denied) {
      // Permissions are denied, next time you could try
      // requesting permissions again (this is also where
      // Android's shouldShowRequestPermissionRationale
      // returned true. According to Android guidelines
      // your App should show an explanatory UI now.
      return Future.error('Location permissions are denied');
    }
  }

  if (permission == LocationPermission.deniedForever) {
    // Permissions are denied forever, handle appropriately.
    return Future.error(
        'Location permissions are permanently denied, we cannot request permissions.');
  }

  // When we reach here, permissions are granted and we can
  // continue accessing the position of the device.
  return await Geolocator.getCurrentPosition();
}

@pragma('vm:entry-point')
void onStart(
  ServiceInstance service,
  // LocationControllerCubit locationControllerCubit,
  // UpdateLocationOnDbCubit updateLocationOnDbCubit,
) async {
  // For flutter prior to version 3.0.0
  // We have to register the plugin manually

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

  double longitude = 0;
  double latitude = 0;


  if (service is AndroidServiceInstance) {
    service.on('start_service').listen((event) async {
      await service.setAsForegroundService();
    });

    service.on('setAsForeground').listen((event) async {
      await service.setAsForegroundService();
    });

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

  service.on("stop_service").listen((event) async {
    await service.stopSelf();
  });

  // bring to foreground
  Timer.periodic(const Duration(seconds: 1), (timer) async {
    if (service is AndroidServiceInstance) {
      if (await service.isForegroundService()) {
        final location = await _determinePosition();
        if (longitude != location.longitude || latitude != location.latitude) {
          longitude = location.longitude;
          latitude = location.latitude;
          flutterLocalNotificationsPlugin.show(
            888,
            'COOL LOCATION SERVICE',
            'Latitude: ${location.latitude}, Longitude: ${location.longitude}',
            const NotificationDetails(
              android: AndroidNotificationDetails(
                'my_foreground',
                'AWESOME SERVICE:',
                icon: 'ic_bg_service_small',
                ongoing: true,
              ),
            ),
            payload: "service",
          );

          print("+++++++++BACKGROUND LOCATION++++++++");
          print(location.latitude);
          print(location.longitude);
        }
      }
    }
  });
}

swayamshreemohanty avatar Nov 07 '22 08:11 swayamshreemohanty

How to work with plugin that don't hace registerWith? I cannot use record (https://pub.dev/packages/record) with flutter_background_service

vietstone-ng avatar Aug 10 '23 09:08 vietstone-ng

@kotoSky 我自己重写了百度地图的flutter插件,可以和flutter_background_service一起用,而且在项目中用起来了

xiaochonzi avatar Aug 17 '23 05:08 xiaochonzi

@kotoSky 厉害

xiaochonzi avatar Aug 21 '23 07:08 xiaochonzi

@xiaochonzi 大佬您的插件我突然发现介绍说只支持安卓,如果不支持苹果那您编写的高德地图是不是安卓苹果都可以用,我要么前台定位换成高德,后台换成百度

kotoSky avatar Aug 22 '23 01:08 kotoSky

@kotoSky ios没有安卓那套机制,后台运行如果app被划掉,就没法后台运行了。(好比使用网易云音乐听歌,如果网易云后台划掉就不能听)所以我只做了安卓部分,另外我觉得百度的定位其实要比高德的好,而且我的那个高德定位插件很久没有更新了。

xiaochonzi avatar Aug 22 '23 14:08 xiaochonzi

@xiaochonzi 如果你想在ios也是用百度地图也简单。找到百度自己写的flutter插件,找到ios部分代码拿过来改一下就行。

xiaochonzi avatar Aug 22 '23 14:08 xiaochonzi

@kotoSky 厉害,可以试试开源一下,我的毕竟是半成品,如果你安卓和ios都搞好了,可以服务更多人

xiaochonzi avatar Sep 02 '23 08:09 xiaochonzi

@xiaochonzi 还得是大佬写的dart端代码稳,让我只是在你代码上cv一下就完成了,但是目前IOS只有一个单次定位功能,我试着把其他功能都弄好再上传一下

kotoSky avatar Sep 04 '23 09:09 kotoSky