5

The title says it all. There is nearly no documentation on flutter's website that shows how to invoke a method in windows native code via a method channel. But I found an issue on the flutter's github that said its possible but there was no code there!

I couldn't find any example projects on github that use windows native code also.

1
  • You might be able to skip the method channel and call the win api directly through ffi, using the win32 plugin. See pub.dev/packages/win32 Commented May 10, 2021 at 1:26

3 Answers 3

16

For that you have to create a method channel in your_flutter_project\windows\runner\flutter_window.cpp.

1. include below modules in the file:

    #include <flutter/binary_messenger.h>
    #include <flutter/standard_method_codec.h>
    #include <flutter/method_channel.h>
    #include <flutter/method_result_functions.h>

2. Then add below method before onCreate() function:

    void initMethodChannel(flutter::FlutterEngine* flutter_instance) {
    // name your channel
    const static std::string channel_name("test_channel");

    auto channel =
        std::make_unique<flutter::MethodChannel<>>(
            flutter_instance->messenger(), channel_name,
            &flutter::StandardMethodCodec::GetInstance());

    channel->SetMethodCallHandler(
        [](const flutter::MethodCall<>& call, 
    std::unique_ptr<flutter::MethodResult<>> result) {

            // cheack method name called from dart
            if (call.method_name().compare("test") == 0) {
            // do whate ever you want

            result->Success("pass result here");
            }
            else {
                result->NotImplemented();
            }
        });
     }

3. Now call this method in the onCreate() function after plugins registration:

    // other codes
    // the plugins registrations
    RegisterPlugins(flutter_controller_->engine());
    // initialize method channel here 
    initMethodChannel(flutter_controller_->engine());

    run_loop_->RegisterFlutterInstance(flutter_controller_->engine());
    // other codes
  • Finally just create a method channel in your dart file and invoke method(in this example 'test' method):

    MethodChannel channel = MethodChannel('test_channel');
    var result = await channel.invokeMethod('test');
    

Here is the complete edited flutter_windows.cpp file:

#include "flutter_window.h"

#include <optional>
#include "flutter/generated_plugin_registrant.h"

#include <flutter/binary_messenger.h>
#include <flutter/standard_method_codec.h>
#include <flutter/method_channel.h>
#include <flutter/method_result_functions.h>

#include <iostream>
using namespace std;

FlutterWindow::FlutterWindow(RunLoop* run_loop,
                             const flutter::DartProject& project)
    : run_loop_(run_loop), project_(project) {}

FlutterWindow::~FlutterWindow() {}


void initMethodChannel(flutter::FlutterEngine* flutter_instance) {

    const static std::string channel_name("test_channel");

    auto channel =
        std::make_unique<flutter::MethodChannel<>>(
            flutter_instance->messenger(), channel_name,
            &flutter::StandardMethodCodec::GetInstance());

    channel->SetMethodCallHandler(
        [](const flutter::MethodCall<>& call, std::unique_ptr<flutter::MethodResult<>> result) {

            if (call.method_name().compare("test") == 0) {
               // do whate ever you want

                result->Success("pass result here");
            }
            else {
                result->NotImplemented();
            }
        });
}

bool FlutterWindow::OnCreate() {
  if (!Win32Window::OnCreate()) {
    return false;
  }
  RECT frame = GetClientArea();

  // The size here must match the window dimensions to avoid unnecessary surface
  // creation / destruction in the startup path.
  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
      frame.right - frame.left, frame.bottom - frame.top, project_);
  // Ensure that basic setup of the controller was successful.
  if (!flutter_controller_->engine() || !flutter_controller_->view()) {
    return false;
  }
  RegisterPlugins(flutter_controller_->engine());
  // initialize method channel here **************************************************
  initMethodChannel(flutter_controller_->engine());

  run_loop_->RegisterFlutterInstance(flutter_controller_->engine());


  SetChildContent(flutter_controller_->view()->GetNativeWindow());
  return true;
}

void FlutterWindow::OnDestroy() {
  if (flutter_controller_) {
    run_loop_->UnregisterFlutterInstance(flutter_controller_->engine());
    flutter_controller_ = nullptr;
  }

  Win32Window::OnDestroy();
}

LRESULT
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
                              WPARAM const wparam,
                              LPARAM const lparam) noexcept {
  // Give Flutter, including plugins, an opporutunity to handle window messages.
  if (flutter_controller_) {
    std::optional<LRESULT> result =
        flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
                                                      lparam);
    if (result) {
      return *result;
    }
  }

  switch (message) {
    case WM_FONTCHANGE:
      flutter_controller_->engine()->ReloadSystemFonts();
      break;
  }

  return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
}
Sign up to request clarification or add additional context in comments.

1 Comment

This probably needs to be updated, since I can't find the run_loop anymore. the FlutterWindow constructor now only contains the DartProject& project
6

The high-level platform channel documentation doesn't yet cover desktop, but the headers for the C++ API here and here have declaration comments that explain their specific uses.

At a high level, the flow is essentially the same as other platforms: from the view controller that you have access to in main you can get the engine, from which you can get the messenger that you need to create a method channel.

For the specifics of calling a method, the unit tests are a source of examples of calling the API different ways.

1 Comment

Thanks a lot. I was able to create some things for method channel but I couldn't create the messenger variable that goes in the argument of method channel. Will try this and verify the answer
3

Yes. The resources are limited. But the Flutter official website does provide some examples for learning:

Comments

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.