How to Use Multiple EventChannel in flutter iOS Native code (Swift)

Viewed 3291

hi I am trying to use multiple event channel to stream data from native side to flutter in iOS swift side when I call the below for setting handler we only get one callback and I want some way to differentiate that which eventsink that I am getting is for Eventchannel1 or EventChannel2

let EventChannel1 = FlutterEventChannel(name: "stream1",binaryMessenger: controller.binaryMessenger)
let EventChannel2 = FlutterEventChannel(name: "stream2",binaryMessenger: controller.binaryMessenger)

EventChannel1.setStreamHandler(self)
EventChannel2.setStreamHandler(self)

then the related callback we get this

  func onListen(withArguments arguments: Any?,
                     eventSink: @escaping FlutterEventSink) -> FlutterError? {
    debugPrint("On Listen Call")
    EventSink = eventSink//this is for the old event channel now I am using 
    //two event channel.
    //and don't know how to know which event channel is which. on flutter 
    //app startup I listen both stream.
    //and the "on Listen Call" which I print to console print two times 
    //which indicate the I am listen to both stream. 
    //but here I don't know how I know if the eventsink is for which event channel.
    //I want some condition here but don,t know how to implement. if possible 
    //something like this if eventchanel.name == eventchannel1 
    //so that I know which event channel event sink it is and handle it according.
    return nil
 }

  func onCancel(withArguments arguments: Any?) -> FlutterError? {
    debugPrint("On cancel Call")
    EventSink = nil
    return nil
 }

if the question is not clear let me know so that I can explain it more clearly .

2 Answers

I loved the problem while looking on GitHub flutter event channel examples and trying different thing. check the below code I add comment so that who ever has the same problem can fixed it easily.

let EventChannel1 = FlutterEventChannel(name: "stream1",binaryMessenger: controller.binaryMessenger)
let EventChannel2 = FlutterEventChannel(name: "stream2",binaryMessenger: controller.binaryMessenger)

EventChannel1.setStreamHandler(self)
EventChannel2.setStreamHandler(self)

func onListen(withArguments arguments: Any?,
                     eventSink: @escaping FlutterEventSink) -> FlutterError? {
    debugPrint("On Listen Call")
    //you see the arguments above this are the one which we can use to know which event channel it is.
    EventSink = eventSink
    return nil
 }

  func onCancel(withArguments arguments: Any?) -> FlutterError? {
    debugPrint("On cancel Call")
    EventSink = nil
    return nil
 }

when you are listening to this stream in flutter side you can pass the parameter there. check the below code.(flutter side code)

static const EventChannel1 = const EventChannel("stream1")
static const EventChannel2 = const EventChannel("stream2")

EventChannel1.receiveBroadcastStream(parameter1).listen(_handlestream1);
//here instead of parameter you can pass integer or string 

EventChannel2.receiveBroadcastStream(parameter2).listen(_handlestream2);
////here instead of parameter you can pass integer or string and that can be use in on listen to check which event channel it is.

Swift Native Code Will Look Like This then .

let EventChannel1 = FlutterEventChannel(name: "stream1",binaryMessenger: controller.binaryMessenger)
let EventChannel2 = FlutterEventChannel(name: "stream2",binaryMessenger: controller.binaryMessenger)

EventChannel1.setStreamHandler(self)
EventChannel2.setStreamHandler(self)

func onListen(withArguments arguments: Any?,
                     eventSink: @escaping FlutterEventSink) -> FlutterError? {
    debugPrint("On Listen Call")

    //here we will check the argument we pass will listen to this eventstream.
    if arguments as? Int == parameter1 { 
        // here you unwrap the argument and check it with parameter you pass
        //if this check pass its mean that its is event channel1 and handle that here
        Evensink1 = eventSink 
    }

    if arguments as? Int == parameter2 {
        //if this check pass mean eventchannel2 and handle that here
        EventSink = eventSink
    }

    return nil
 }

  func onCancel(withArguments arguments: Any?) -> FlutterError? {
    debugPrint("On cancel Call")
    EventSink = nil
    return nil
 }

if you need any further help let me know I am here to help.

Thanks for this answer. The solution works well. I still got some warnings when using it. This was because I updated the state of a Widget based on the eventChannel stream. You might get memory leaks when moving to a new screen if the event channel listener is not cancelled. I used a solution like this instead:

static const EventChannel1 = const EventChannel("stream1")
static const EventChannel2 = const EventChannel("stream2")

StreamSubscription eventChannelListener1 = EventChannel1.receiveBroadcastStream(parameter1).listen(_handlestream1, onError: _onError);
StreamSubscription eventChannelListener2 = EventChannel2.receiveBroadcastStream(parameter2).listen(_handlestream2, onError: _onError);

The dispose function of the StatefulWidget looks like:

 @override
  void dispose() {
    super.dispose();      
     eventChannelListener1.cancel();
     eventChannelListener2.cancel();
    }
  }
Related