rmawatson / flutter_isolate

Launch an isolate that can use flutter plugins.
MIT License
263 stars 80 forks source link

Plugins not working in an FlutterIsolate #103

Closed Christer-Muntean closed 2 years ago

Christer-Muntean commented 2 years ago

Hi I'm having trouble with this plugin, it doesn't seem to work with other plugins. Am I doing something wrong?

Error:

[VERBOSE-2:dart_isolate.cc(1111)] Unhandled exception:
'package:flutter/src/services/platform_channel.dart': Failed assertion: line 134 pos 7: '_binaryMessenger != null || ServicesBinding.instance != null': Cannot use this MethodChannel before the binary messenger has been initialized. This happens when you invoke platform methods before the WidgetsFlutterBinding has been initialized. You can fix this by either calling WidgetsFlutterBinding.ensureInitialized() before this or by passing a custom BinaryMessenger instance to MethodChannel().
#0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:51:61)
#1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
#2      MethodChannel.binaryMessenger (package:flutter/src/services/platform_channel.dart:134:7)
#3      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:167:36)
#4      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:350:12)
#5      MethodChannel.invokeListMethod (package:flutter/src/services/platform_channel.dart:363:41)
#6      MethodChannelFirebase._initializeCore (package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart:31:37)
#7      MethodChannelFirebase.initializeApp (package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart:73:13)

Performing await Firebase.initializeApp(); in the isolate is causing the error. Also await SharedPreferences.getInstance() causes the same error (and probably many more plugins as well).

static void songDelegator(SendPort isolateToMainStream) async {
    SongInfo? songInfo;

    var mainToIsolateStream = ReceivePort();
    isolateToMainStream.send(mainToIsolateStream.sendPort);

    mainToIsolateStream.listen((data) async {
      if(data is SongInfo){
        songInfo = data;
      } else if (data == 'INITIALIZE_FIREBASE'){
        await Firebase.initializeApp();
      }
    });
}

I also have this in main.dart

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  ...

My plugins are:

  flutter_isolate: ^2.0.2-pre
  firebase_core: ^1.10.0
  cloud_firestore: ^3.1.9
  shared_preferences: ^2.0.8

I spawn the isolate like so in App() statefulwidget:


  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance?.addPostFrameCallback((_) {
      setIsolate();
    });
  }

  void setIsolate() async {
    mainToIsolateStream = await initIsolate();
    mainToIsolateStream.send('INITIALIZE_FIREBASE');
  }

Future<dynamic> initIsolate() async {
    Completer completer = Completer<SendPort>();
    var isolateToMainStream = ReceivePort();

    isolateToMainStream.listen((data) {
      if (data is SendPort) {
        var mainToIsolateStream = data;
        completer.complete(mainToIsolateStream);
      } else {
        //Do something
      }
    });

    await Isolate.spawn(MyCubit.songDelegator, isolateToMainStream.sendPort);
    return completer.future;
  }
Christer-Muntean commented 2 years ago

Omg. Turns out I didn't use FlutterIsloate to spawn isolate...

await FlutterIsolate.spawn(MyCubit. songDelegator, isolateToMainStream.sendPort);