Skip to content
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

MissingPluginException when using in isolate with Android Alarm Service #220

Closed
estevez-dev opened this issue Aug 28, 2019 · 32 comments
Closed

Comments

@estevez-dev
Copy link

Describe the bug
I'm trying to get device location in a callback of android_alarm_service. So I create a new alarm:

AndroidAlarmManager.periodic(
              Duration(minutes: 1),
              1,
              updateDeviceLocation,
              wakeup: true,
            );

Then updateDeviceLocation is called in a separate isolate in this case. Here is the function:

static void updateDeviceLocation() {
    print("Starting device location update...");
    SharedPreferences.getInstance().then((prefs){
      print("... loading settings");
      String url = prefs.getString('app-webhook-url');
      if (url != null && url.isNotEmpty) {
        print("... done. Getting device location...");
        try {
          var location = new Location();
          location.getLocation().then((currentLocation){
            print("... done. Sending data home...");
            Map<String, String> headers = {};
            headers["Content-Type"] = "application/json";
            var data = {
              "type": "update_location",
              "data": {
                "gps": [currentLocation.latitude, currentLocation.longitude],
                "gps_accuracy": currentLocation.accuracy,
                "battery": 45
              }
            };
            http.post(
                url,
                headers: headers,
                body: json.encode(data)
            );
          });
        } on PlatformException catch (e) {
          if (e.code == 'PERMISSION_DENIED') {
            print("... no location permission. Aborting");
          }
        }
      } else {
        print("... no webhook. Aborting");
      }
    });
  }

If I call updateDeviceLocation directly in main isolate all works fine. But when updateDeviceLocation called by Alarm Manager in a separate isolate I'm getting:

Unhandled Exception: MissingPluginException(No implementation found for method getLocation on channel lyokone/location)

I tried flutter clean, restarting and rebuilding everything, but no luck.

Expected behavior
I hope this plugin can work fine in a separate isolate.

Tested on:

  • Android 9, API Level 28, real device

Additional logs

I/flutter (14499): Starting device location update...
I/flutter (14499): ... loading settings
I/flutter (14499): ... checking settings
I/flutter (14499): ... done. Getting device location...
E/flutter (14499): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: MissingPluginException(No implementation found for method getLocation on channel lyokone/location)
E/flutter (14499): #0      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:314:7)
E/flutter (14499): <asynchronous suspension>
E/flutter (14499): #1      Location.getLocation (package:location/location.dart:61:8)
E/flutter (14499): #2      PremiumFeaturesManager.updateDeviceLocation.<anonymous closure> (package:hass_client/premium_features_manager.class.dart:22:20)
E/flutter (14499): #3      _rootRunUnary (dart:async/zone.dart:1132:38)
E/flutter (14499): #4      _CustomZone.runUnary (dart:async/zone.dart:1029:19)
E/flutter (14499): #5      _FutureListener.handleValue (dart:async/future_impl.dart:126:18)
E/flutter (14499): #6      Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:639:45)
E/flutter (14499): #7      Future._propagateToListeners (dart:async/future_impl.dart:668:32)
E/flutter (14499): #8      Future._complete (dart:async/future_impl.dart:473:7)
E/flutter (14499): #9      _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
E/flutter (14499): #10     _AsyncAwaitCompleter.complete.<anonymous closure> (dart:async-patch/async_patch.dart:33:20)
E/flutter (14499): #11     _rootRun (dart:async/zone.dart:1120:38)
E/flutter (14499): #12     _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter (14499): #13     _CustomZone.runGuarded (dart:async/zone.dart:923:7)
E/flutter (14499): #14     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:963:23)
E/flutter (14499): #15     _rootRun (dart:async/zone.dart:1124:13)
E/flutter (14499): #16     _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter (14499): #17     _CustomZone.runGuarded (dart:async/zone.dart:923:7)
E/flutter (14499): #18     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:963:23)
E/flutter (14499): #19     _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (14499): #20     _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
@stale
Copy link

stale bot commented Sep 27, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@timrijckaert
Copy link

The plugin simply does not register itself when it has no Activity Context.

public static void registerWith(Registrar registrar) {
  if(registrar.activity() != null) {
    ...
  }
}

@stale stale bot removed the inactive label Oct 2, 2019
@stale
Copy link

stale bot commented Nov 1, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the inactive label Nov 1, 2019
@timrijckaert
Copy link

Prevent closing

@stale
Copy link

stale bot commented Dec 1, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the inactive label Dec 1, 2019
@timrijckaert
Copy link

Prevent closing

@stale stale bot removed the inactive label Dec 2, 2019
@shanazainab
Copy link

2:35:37.911 592 info flutter.tools [ +192 ms] E/flutter (23714): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: MissingPluginException(No implementation found for method getLocation on channel lyokone/location)

@shanazainab
Copy link

I am getting the same issue, even with geolocator plugin also, Same error when used with android alarm manager

@stale
Copy link

stale bot commented Jan 3, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the inactive label Jan 3, 2020
@stale stale bot closed this as completed Jan 10, 2020
@codesxt
Copy link

codesxt commented Feb 3, 2020

Prevent closing

@Lyokone
Copy link
Owner

Lyokone commented Feb 4, 2020

Hey ! Sorry for the huge delay in response, I was mostly away from my computer this last months. I'll look into that as soon as possible !

@Lyokone Lyokone reopened this Feb 4, 2020
@stale stale bot removed the inactive label Feb 4, 2020
@Lyokone
Copy link
Owner

Lyokone commented Feb 23, 2020

Hey, I've just updated the plugin to version 2.5.0, which supports embedding V2, according to this, it should be working fine without any more work. Please let me know if it fixed the issue :)

@Lyokone Lyokone added the bug label Feb 23, 2020
@estevez-dev
Copy link
Author

Nice! Thanks a lot @Lyokone !
Will try it this week.

@sanchitd5
Copy link

Hi I am having the same problem when using the package with other packages like android_alarm_manager, foreground_service and background_fetch

I have also attached a screenshot of the logs as well.

image

@Lyokone
Copy link
Owner

Lyokone commented Feb 26, 2020

@sanchitd5 Have you upgraded your project to Android Embedding V2 ? https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects

@sanchitd5
Copy link

@Lyokone Yes, I have created a new project using "flutter create -i objc -a java" . it is still giving the same issue.

@Lyokone
Copy link
Owner

Lyokone commented Feb 26, 2020

Would you mind providing a project showing the error ? It would be easier for me to help you.

@sanchitd5
Copy link

@Lyokone I have invited you to the repo "https://github.com/sanchitd5/flutter_bluetoothScanner/tree/locationEmit-locationPackage" this branch is the one with the code in it "locationEmit-locationPackage".

Also, this is the path for the exact file where the code is lib/utils/AndroidAlarmBootstrapper/AlarmManagerBootstraper.dart

@Lyokone
Copy link
Owner

Lyokone commented Feb 29, 2020

I've tested with a small project and it seems that the Android activity isn't set when the plugin is running in isolate. I have a couple of idea that I'll try to resolve this :)

@estevez-dev
Copy link
Author

estevez-dev commented Mar 21, 2020

Hi @Lyokone
I'm trying to move back from geolocator plugin to location. Indeed there is no issue with MissingPluginException when running in separate isolate, but PlatformException NO_ACTIVITY still the case =(
I'm now using workmanager plugin instead of alarm manager.

@Lyokone
Copy link
Owner

Lyokone commented Mar 26, 2020

Hey ! Not sure what causing this and how to force the plugin to get an Activity :/ Were you able to get a location fix with geolocator ?

@estevez-dev
Copy link
Author

Geolocator is working without Activity, but it has another issue now =(

@julien-h
Copy link

any updates on this ? I get the same error using the plugin foreground_service to run in background

@gidyon
Copy link

gidyon commented May 8, 2020

The same behaviour is observed when used with firebase messaging onBackground callback

@praveenbbhati
Copy link

Any update on this?
MissingPluginException(No implementation found for method getLocation on channel lyokone/location)

@jafar96
Copy link

jafar96 commented May 31, 2020

Hey guys. I have the same problem. what should I do to fix it ?
can anybody help me ?

@jafar96
Copy link

jafar96 commented May 31, 2020

Hey guys. I have the same problem. what should I do to fix it ?
can anybody help me ?

additionally I tried to solve this problem by using Java native code. but didn't work.

@deiviszi
Copy link

deiviszi commented Jun 2, 2020

Hello, I am also having the same problem when I try to use location with the android_alarm_manager plugin.

@jafar96
Copy link

jafar96 commented Jun 2, 2020

Hey guys.
I finally fixed this problem. I used background_fetch package into android_alarm_manager and worked for me. you can do following steps :

Note : since I need to get Location every 1 minute and minimum period of background_fetch is 15 minutes , I do this. in other words I start and stop background_fetch every 1 minute by android_alarm_manager.

in main.dart :

main.dart

void getLocation() async{
  Location location = Location();
  LocationData locationData = await location.getLocation();
  print(locationData.latitude);
  // do something else
}

void myAlarmManager()async {
        BackgroundFetch.scheduleTask(TaskConfig(
          taskId: 'getLocation',
          delay: 1000,
          enableHeadless: true,
          stopOnTerminate: false,
          forceAlarmManager: true,
          startOnBoot: true,
        ));
}

void backgroundFetchHeadlessTask(String taskId) async {
  print("[BackgroundFetch] Headless event received: $taskId");
  getLocation();
  BackgroundFetch.finish(taskId);
  BackgroundFetch.stop();
}

void main() async{
  final backgroundLocationID = 0;
  WidgetsFlutterBinding.ensureInitialized();
  await AndroidAlarmManager.initialize();
  runApp(InspectorApp());
  BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
  await AndroidAlarmManager.periodic(
    const Duration(minutes: 1),
    backgroundLocationID,
    myAlarmManager,
    rescheduleOnReboot: true,
  );
}

.......
class MyAppState extends State{
 
 ......
  @override
  void initState() {
    initPlatformState();
    super.initState();
  }
  

  void initPlatformState() async {
    // Configure BackgroundFetch.
    BackgroundFetch.configure(BackgroundFetchConfig(
      minimumFetchInterval: 15,
      forceAlarmManager: false,
      stopOnTerminate: false,
      startOnBoot: true,
      enableHeadless: true,
      requiresBatteryNotLow: false,
      requiresCharging: false,
      requiresStorageNotLow: false,
      requiresDeviceIdle: false,
      requiredNetworkType: NetworkType.ANY,
    ), _onBackgroundFetch).then((int status) {
      print('[BackgroundFetch] configure success: $status');
    }).catchError((e) {
      print('[BackgroundFetch] configure ERROR: $e');
    });
    if (!mounted) return;
  }

  void _onBackgroundFetch(String taskId) async {
    print("[BackgroundFetch] Event received: $taskId");
    getLocation();
    BackgroundFetch.finish(taskId);
    BackgroundFetch.stop();
  }

}

create a new class and named it MyApplication.java.

MyApplication.java

package yourPackageName;

import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin;
import io.flutter.plugins.androidalarmmanager.AlarmService;
import io.flutter.plugins.androidalarmmanager.AndroidAlarmManagerPlugin;
import com.lyokone.location.LocationPlugin;
import com.transistorsoft.flutter.backgroundfetch.BackgroundFetchPlugin;

public class MyApplication extends FlutterApplication implements PluginRegistrantCallback {
    @Override
    public void onCreate() {
        super.onCreate();
        AlarmService.setPluginRegistrant(this);
    }

    @Override
    public void registerWith(PluginRegistry registry) {
        AndroidAlarmManagerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.androidalarmmanager.AndroidAlarmManagerPlugin"));
        SharedPreferencesPlugin.registerWith(registry.registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin"));
        LocationPlugin.registerWith(registry.registrarFor("com.lyokone.location.LocationPlugin"));
        BackgroundFetchPlugin.registerWith(registry.registrarFor("com.transistorsoft.flutter.backgroundfetch.BackgroundFetchPlugin"));
    }
}

and set name attribute in application tag to ".MyApplication"

I hope to work for you

@estevez-dev
Copy link
Author

estevez-dev commented Jun 4, 2020

@jafar96 this is very strange solution as background_fetch uses JobScheduler under the hood - the API similar to AlarmManager. So you are scheduling a background task the will schedule a background task... Also it will not work for Android older than 5.0 because background_fetch uses AlarmManager for old Android versions.

@stale
Copy link

stale bot commented Jul 4, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the inactive label Jul 4, 2020
@stale stale bot closed this as completed Jul 11, 2020
@aidooyaw1992
Copy link

@jafar96 its a good approach but its too much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests