0

I created Flutter plugin. But I also need to add more channels. So I created both dart code and the native implementation. The problem is that the dart code cannot find the native implementation, so it throw out error with the message "Unhandled exception: MissingPluginException (No implementation found for method ...)"

I compared my native implementation with the boilerplate implementation, I don't see anything wrong. I have the correct channel name. I have registered the channel. My channel name is certainly different from the builderplate implementation's channel name. But it matches the one in dart code.

I wonder if I need to have all my native implementations to have the same channel name even though they represent different functionality blocks?

12
  • You can have more than one method channel. There must be something wrong with your code. stackoverflow.com/questions/62548667/… Commented Jul 7, 2022 at 21:43
  • @Colin Thank you for the link. But it is not very helpful. I have created the channel. To follow the boilerplate native implementation which has an .h and a .m file (iOS objective c), I created another set of .h and .m files. Inside the .m file, I have registerWithRegistra method which created a channel with a different channel name. It is this new files I think cannot be found. I tried to change the boilerplate's .h and .m files by changing the file names and class names a little, then I got the error: Build input file cannot be found", pointing to the where my old boilerplate .m should be. Commented Jul 8, 2022 at 1:45
  • I think the .h and .m files must have been registered somewhere so that when building the project, it knows where to find them. But because I changed the file name (class name also) a little, they cannot be found. But once I changed back the names, build was successful. Commented Jul 8, 2022 at 1:47
  • I think the pluginClass in pubspec.yaml is where the build process looks for the native implementation. Currently, it has only the boilerplate class name. My question is: Can I add more pluginClass inside pubspec.yaml? Commented Jul 8, 2022 at 2:00
  • I tried to add another: pluginClass: 'ImplementationClass', but it didn't work. Then I tried to add the class next to the original (boilerplate implementation class) separated by comma, and it still didn't work. Does this mean all the channels have to be defined in one implementation file? Commented Jul 8, 2022 at 2:07

1 Answer 1

1

You can create multiple MethodChannels for your plugin and assign an individual MethodCallHandler to each MethodChannel. That way you can handle two methods with the same name differently if they are in different channels.

Here is how I've changed the Flutter plugin template to support multiple MethodChannels.

P.S.: I've used the Flutter 2.10.5 plugin template because it's a bit easier to understand. In Flutter 3 they've added an interface on the Dart side.

Dart:

class ExamplePlugin {
  static const MethodChannel _channel = MethodChannel('example_plugin');
  static const MethodChannel _channel2 = MethodChannel('example_plugin2');

  static Future<String?> get platformVersion async {
    final String? version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }

  static Future<String?> get helloWorld async {
    final String? helloWorld = await _channel2.invokeMethod('getHelloWorld');
    return helloWorld;
  }
}

Kotlin:

class ExamplePlugin: FlutterPlugin {
  private lateinit var channel : MethodChannel
  private lateinit var channel2 : MethodChannel

  private val firstMethodCallHandler = FirstMethodCallHandler()
  private val secondMethodCallHandler = SecondMethodCallHandler()

  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    channel = MethodChannel(flutterPluginBinding.binaryMessenger, "example_plugin")
    channel.setMethodCallHandler(firstMethodCallHandler)

    channel2 = MethodChannel(flutterPluginBinding.binaryMessenger, "example_plugin2")
    channel2.setMethodCallHandler(secondMethodCallHandler)
  }

  override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
    channel2.setMethodCallHandler(null)
  }

  private inner class FirstMethodCallHandler: MethodCallHandler {
    override fun onMethodCall(call: MethodCall, result: Result) {
      if (call.method == "getPlatformVersion") {
        result.success("Android ${android.os.Build.VERSION.RELEASE}")
      } else {
        result.notImplemented()
      }
    }
  }

  private inner class SecondMethodCallHandler: MethodCallHandler {
    override fun onMethodCall(call: MethodCall, result: Result) {
      if (call.method == "getHelloWorld") {
        result.success("Hello World!")
      } else {
        result.notImplemented()
      }
    }
  }
}

Swift:

public class SwiftExamplePlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "example_plugin", binaryMessenger: registrar.messenger())
    let channel2 = FlutterMethodChannel(name: "example_plugin2", binaryMessenger: registrar.messenger())
    
    channel.setMethodCallHandler(firstMethodCallHandler)
    channel2.setMethodCallHandler(secondMethodCallHandler)
  }

  static public func firstMethodCallHandler(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    result("iOS " + UIDevice.current.systemVersion)
  }
    
  static public func secondMethodCallHandler(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    result("Hello World!")
  }
}

Complete source code: https://github.com/ColinSchmale/example_plugin

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, Colin! This is very helpful. I will never be able to think of doing it this way. I happened to use Flutter 3. The native implementation class is already fixed to use only one channel. But from your example, I can modify mine to have multiple channels.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.