lamnhan066 / isolate_manager

Create multiple long-lived isolates for the Functions, supports Worker on the Web (with the effective generator) and WASM compilation.
https://pub.dev/packages/isolate_manager
MIT License
37 stars 2 forks source link

[Flutter Issue] Unable receive Platform Channel calls in background isolates #5

Open prasant10050 opened 1 year ago

prasant10050 commented 1 year ago

Bad state: The BackgroundIsolateBinaryMessenger.instance value is invalid until BackgroundIsolateBinaryMessenger.ensureInitialized is executed.

lamnhan066 commented 1 year ago

Hi, please give me a minimal code that causes the issue so I can easier to resolve it. Thanks.

deckerst commented 1 year ago

Same here. It happens when using a plugin within the isolate.

...
  void runInService() {
    final isolateManager = IsolateManager.create(runCommand)..start();
    isolateManager.compute("-version").then((output) {
        if (output != null) {
          appendOutput(output);
        }
        isolateManager.stop();
      });
  }
}

@pragma('vm:entry-point')
Future<String?> runCommand(String command) async {
  final session = await FFmpegKit.execute(command);
  return await session.getOutput();
}

To address OP issue, one can pass the token and initialize the messenger in the isolate:

...
  void runInService() {
    final isolateManager = IsolateManager.create(runCommand)..start();
    isolateManager.compute(_Args(RootIsolateToken.instance!, "-version")).then((output) {
      if (output != null) {
        appendOutput(output);
      }
      isolateManager.stop();
    });
  }

  String getOutputText() => _outputText;
}

class _Args {
  final RootIsolateToken rootIsolateToken;
  final String command;

  const _Args(this.rootIsolateToken, this.command);
}

@pragma('vm:entry-point')
Future<String?> runCommand(_Args args) async {
  BackgroundIsolateBinaryMessenger.ensureInitialized(args.rootIsolateToken);
  final session = await FFmpegKit.execute(args.command);
  return await session.getOutput();
}

This works for plugins that only do dart -> platform messenging. But if the plugin also does platform -> dart messenging, you'll get an exception like so:

E/flutter ( 6872): Unsupported operation: Background isolates do not support setMessageHandler(). Messages from the host platform always go to the root isolate.
E/flutter ( 6872): #0      BackgroundIsolateBinaryMessenger.setMessageHandler (package:flutter/src/services/_background_isolate_binary_messenger_io.dart:94:5)
E/flutter ( 6872): #1      EventChannel.receiveBroadcastStream.<anonymous closure> (package:flutter/src/services/platform_channel.dart:639:23)
E/flutter ( 6872): #2      _runGuarded (dart:async/stream_controller.dart:823:24)
E/flutter ( 6872): #3      _BroadcastStreamController._subscribe (dart:async/broadcast_stream_controller.dart:207:7)
E/flutter ( 6872): #4      _ControllerStream._createSubscription (dart:async/stream_controller.dart:836:19)
E/flutter ( 6872): #5      _StreamImpl.listen (dart:async/stream_impl.dart:471:9)
...
lamnhan066 commented 1 year ago

@deckerst this is a known issue of the Flutter. I think we need to wait for the Flutter team to resolve this issue first.