c++flutterflutter-plugin

invokeMethod from windows host to Flutter client: how to send return value?


In Flutter it is possible to develop plugins for executing platform specific code. For example on a windows host it is possible to invoke c++ code from the Flutter client with:

final int result = await platform.invokeMethod('getBatteryLevel');

At the windows host you can send a reply to this call for example with:

channel.SetMethodCallHandler(
    [](const flutter::MethodCall<>& call,
      std::unique_ptr<flutter::MethodResult<>> result) {
        if (call.method_name() == "getBatteryLevel") {
          int battery_level = GetBatteryLevel();
          if (battery_level != -1) {
            result->Success(battery_level);
          }
          else {
            result->Error("UNAVAILABLE", "Battery level not available.");
          }
        }
        else {
          result->NotImplemented();
        }
    });

I want to go the other direction. The following code sends the battery level from the host to the Flutter client:

int battery_level = GetBatteryLevel();
method_channel_->InvokeMethod(
                "sendBatteryLevel",
                std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
                    {flutter::EncodableValue("batteryLevel"), flutter::EncodableValue(battery_level)},
                }));
//string answer = await a string answer from method_channel_

But how can I send a return value back from the client to the host? I want to answer this call on the client, for example like

_handleMethodCall(MethodCall call) async {
    switch (call.method) {
      case "batteryLevel":
        final args = call.arguments as Map;
        final batteryLevel= args['batteryLevel'] as int;
        //Send return value
        call.answer('Thank you for informing me!'); //not working, this is what I want to do
        break;
    }
}

The method InvokeMethod(...) from flutter::MethodChannel has a flutter::MethodResult parameter. But i didn't manage to to call it properly in order to receive a return value for the call from the flutter client

Update: I tried smorgans suggestion already using this client code:

_handleMethodCall(MethodCall call) async {
    switch (call.method) {
      case "batteryLevel":
        final args = call.arguments as Map;
        final batteryLevel= args['batteryLevel'] as int;
        //Send return value
        return 'Thank you for informing me!'; //I want to receive this string at the C++ host code
    }
}

My problem is that i don't get the C++ host code working to receive the answer. I tried the following:

int battery_level = GetBatteryLevel();
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> resultPointer; // How do I declare this properly?
method_channel_->InvokeMethod(
                "sendBatteryLevel",
                std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
                    {flutter::EncodableValue("batteryLevel"), flutter::EncodableValue(battery_level)},
                }), resultPointer);
//std::string answer = exctractAnswerFromMethodResult(resultPointer); // how do I do this?

I tried to receive the answer as shown above, but i didn't manage to pass the MethodResult parameter properly to method_channel_->InvokeMethod. The code from above results in the this compiler error:

Compiler Error


Solution

  • On the Dart side:

    As it says in the MethodChannel documentation:

    If the future returned by the handler completes with a result, that value is sent back to the platform plugin caller

    Your call.answer line (which doesn't work because there is no such method on MethodCall) should just be a return.

    On the C++ side:

    MethodResult is an abstract class, so you cannot instantiate it. You need to either make your own subclass with the functionality you want and instantiate that, or use the provided MethodResultFunctions class if you want to use lambdas instead.

    You also need to std::move the object you declare when you pass it, since it's a unique_ptr; you are passing ownership of the handler to the method.

    The method channel unit tests might be useful as examples, but it also looks like you may want to spend some time with some general C++ class tutorials. Using these C++ APIs correctly is going to require require familiarity with core C++ concepts like classes and unique_ptr.