-
Notifications
You must be signed in to change notification settings - Fork 125
MissingPluginException thrown when starting the foreground service #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The Geolocator plugin doesn't seem to have good compatibility with this plugin. How about using the fl_location plugin which does the same thing? Here's an example code: import 'dart:async';
import 'dart:isolate';
import 'package:fl_location/fl_location.dart';
import 'package:flutter/material.dart';
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
void main() => runApp(const ExampleApp());
// The callback function should always be a top-level function.
void startCallback() {
// The setTaskHandler function must be called to handle the task in the background.
FlutterForegroundTask.setTaskHandler(MyTaskHandler());
}
class MyTaskHandler extends TaskHandler {
StreamSubscription<Location>? _streamSubscription;
@override
Future<void> onStart(DateTime timestamp, SendPort? sendPort) async {
_streamSubscription = FlLocation.getLocationStream().listen((event) {
FlutterForegroundTask.updateService(
notificationTitle: 'My Location',
notificationText: '${event.latitude}, ${event.longitude}',
);
// Send data to the main isolate.
sendPort?.send(event);
});
}
@override
Future<void> onEvent(DateTime timestamp, SendPort? sendPort) async {
}
@override
Future<void> onDestroy(DateTime timestamp, SendPort? sendPort) async {
await _streamSubscription?.cancel();
}
}
class ExampleApp extends StatelessWidget {
const ExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: ExamplePage(),
);
}
}
class ExamplePage extends StatefulWidget {
const ExamplePage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _ExamplePageState();
}
class _ExamplePageState extends State<ExamplePage> {
ReceivePort? _receivePort;
Future<bool> _checkAndRequestPermission({bool? background}) async {
if (!await FlLocation.isLocationServicesEnabled) {
// Location services are disabled.
return false;
}
var locationPermission = await FlLocation.checkLocationPermission();
if (locationPermission == LocationPermission.deniedForever) {
// Cannot request runtime permission because location permission is denied forever.
return false;
} else if (locationPermission == LocationPermission.denied) {
// Ask the user for location permission.
locationPermission = await FlLocation.requestLocationPermission();
if (locationPermission == LocationPermission.denied ||
locationPermission == LocationPermission.deniedForever) return false;
}
// Location permission must always be allowed (LocationPermission.always)
// to collect location data in the background.
if (background == true &&
locationPermission == LocationPermission.whileInUse) return false;
// Location services has been enabled and permission have been granted.
return true;
}
Future<void> _initForegroundTask() async {
await FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions(
channelId: 'notification_channel_id',
channelName: 'Foreground Notification',
channelDescription:
'This notification appears when the foreground service is running.',
channelImportance: NotificationChannelImportance.LOW,
priority: NotificationPriority.LOW,
),
foregroundTaskOptions: const ForegroundTaskOptions(
autoRunOnBoot: true,
allowWifiLock: true,
),
printDevLog: true,
);
}
Future<bool> _startForegroundTask() async {
if (await _checkAndRequestPermission(background: true) == false) {
print('Location permission denied!!');
return false;
}
ReceivePort? receivePort;
if (await FlutterForegroundTask.isRunningService) {
receivePort = await FlutterForegroundTask.restartService();
} else {
receivePort = await FlutterForegroundTask.startService(
notificationTitle: 'Foreground Service is running',
notificationText: 'Tap to return to the app',
callback: startCallback,
);
}
return _registerReceivePort(receivePort);
}
Future<bool> _stopForegroundTask() async {
return await FlutterForegroundTask.stopService();
}
bool _registerReceivePort(ReceivePort? receivePort) {
_closeReceivePort();
if (receivePort != null) {
_receivePort = receivePort;
_receivePort?.listen((message) {
if (message is Location) {
print('location: ${message.toJson()}');
}
});
return true;
}
return false;
}
void _closeReceivePort() {
_receivePort?.close();
_receivePort = null;
}
@override
void initState() {
super.initState();
_initForegroundTask();
WidgetsBinding.instance?.addPostFrameCallback((_) async {
// You can get the previous ReceivePort without restarting the service.
if (await FlutterForegroundTask.isRunningService) {
final newReceivePort = await FlutterForegroundTask.receivePort;
_registerReceivePort(newReceivePort);
}
});
}
@override
void dispose() {
_closeReceivePort();
super.dispose();
}
@override
Widget build(BuildContext context) {
// A widget that prevents the app from closing when the foreground service is running.
// This widget must be declared above the [Scaffold] widget.
return WithForegroundTask(
child: Scaffold(
appBar: AppBar(
title: const Text('Flutter Foreground Task'),
centerTitle: true,
),
body: _buildContentView(),
),
);
}
Widget _buildContentView() {
buttonBuilder(String text, {VoidCallback? onPressed}) {
return ElevatedButton(
child: Text(text),
onPressed: onPressed,
);
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
buttonBuilder('start', onPressed: _startForegroundTask),
buttonBuilder('stop', onPressed: _stopForegroundTask),
],
),
);
}
} |
I had to update the onRequestPermissionsResult in the LocationPermission.kt file to match its signature but other than that everything works perfectly (still didn't test it on ios though). Thank you for the support !! <3 |
Hi, I have this same issue with Geolocator. I have a bunch of other plugins that also throw MissingPluginExceptions in the foreground service and I'm trying to understand why. |
Hi, any news on this? Reference link. |
@irjayjay Yes this plugin doesn't support Geolocator, it worked for me with fl_location, but i had to open to kotlin files and change the signature of some methods. To be honest if you're looking for a production grade plugin the only one available is flutter_background_geolocator (and it has its drawbacks) and it required a licence on android (300$) but it doesn't require one for debug build. If you really need access to background geolocation and want to trigger callbacks (like saving in local db or alerting the user when he reaches his destination) then this is the only solution currently available in flutter. Hope i answered your questions |
I'd like to use geolocation on foreground/background services as well. Though manually changing cached kotlin files can get cumbersome. Could you perhaps raise it as an issue in their following repo? |
Better context for future reference: WARNING: Before attempting this fix: our team has found Flutter 3 highly unstable, especially when using any map plugins such as mapbox/gmaps/etc. Various crashes have forced us to remain on an earlier version of Flutter. Solution is to upgrade to Flutter 3 and run: The issue is better solved by both upgrading to Flutter 3 and upgrading flutter_foreground_task to version 3.8.1, then you don't have to run |
Uh oh!
There was an error while loading. Please reload this page.
I followed this example:
Got this exception :
The following MissingPluginException was thrown while activating platform stream on channel
flutter.baseflow.com/geolocator_updates:
MissingPluginException(No implementation found for method listen on channel
flutter.baseflow.com/geolocator_updates)
When the exception was thrown, this was the stack:
#0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:175:7)
#1 EventChannel.receiveBroadcastStream.
(package:flutter/src/services/platform_channel.dart:516:9)
The text was updated successfully, but these errors were encountered: