Search code examples
c++flutterflutter-windowsflutter-platform-channel

Flutter platform-channel on windows


I need to access Windows Desktop API to change network settings. I have read flutter document and experiences with flutter platform channel. When I ran the code, I just got true in output, but I expect receiving string message from host.

Any help would be appreciated.

windows/runner/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(const flutter::DartProject& project)
    : project_(project) {}

FlutterWindow::~FlutterWindow() {}
void initMethodChannel(flutter::FlutterEngine* flutter_instance) {
    const static std::string channel_name("test_channel");
    flutter::BinaryMessenger *messenger = FlEngine->messenger();
    const flutter::StandardMethodCodec *codec = &flutter::StandardMethodCodec::GetInstance();
    auto channel = std::make_unique<flutter::MethodChannel<>>(messenger ,channel_name ,codec);

    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) {

                // check method name called from dart
                if (call.method_name().compare("test") == 0) {
                // do what ever you want
                res = flutter::EncodableValue("Channel is working!");
                result->Success(res);
                }
                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());
  initMethodChannel(flutter_controller_->engine());
  SetChildContent(flutter_controller_->view()->GetNativeWindow());

  flutter_controller_->engine()->SetNextFrameCallback([&]() {
    this->Show();
  });

  return true;
}

void FlutterWindow::OnDestroy() {
  if (flutter_controller_) {
    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 opportunity 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);
}

Calling the platform and method channel in dart

MethodChannel channel = const MethodChannel('test_channel');
print(await channel.invokeMethod("test"));

Output

flutter: true

But expect getting Channel is working! in the output.


Solution

  • There were some errors in the flutter_window.cpp file:

    1- Missing Header Inclusion

    I added these headers at the top of the file:

    • #include <string>
    • #include <flutter/encodable_value.h>
    • #include <../standard_codec.cc>
    • #include "windows.h"
    • #include "windef.h"
    • #include "windowsx.h"

    And removed these headers:

    • #include <iostream>
    • using namespace std;

    2- Duplicated channel declaration:

    This is what I need in this situation:

    auto channel = std::make_unique<flutter::MethodChannel<>>(messenger ,channel_name ,codec);
    

    3- Undefined res variable:

    just defined it as below, before using it:

    flutter::EncodableValue res;
    res = flutter::EncodableValue("pass result here");
    result->Success(res);
    

    After all of those changes, It got working fine.

    The final flutter_window.cpp file is like that:

    #include "flutter_window.h"
    #include <optional>
    #include "flutter/generated_plugin_registrant.h"
    
    #include <string>
    #include <flutter/binary_messenger.h>
    #include <flutter/standard_method_codec.h>
    #include <flutter/method_channel.h>
    #include <flutter/method_result_functions.h>
    #include <flutter/encodable_value.h>
    #include <../standard_codec.cc>
    #include "windows.h"
    #include "windef.h"
    #include "windowsx.h"
    
    FlutterWindow::FlutterWindow(const flutter::DartProject& project)
        : project_(project) {}
    
    FlutterWindow::~FlutterWindow() {}
    void initMethodChannel(flutter::FlutterEngine* flutter_instance) {
        const static std::string channel_name("test");
        flutter::BinaryMessenger* messenger = flutter_instance->messenger();
        const flutter::StandardMethodCodec* codec = &flutter::StandardMethodCodec::GetInstance();
        auto channel = std::make_unique<flutter::MethodChannel<>>(messenger ,channel_name ,codec);
    
            channel->SetMethodCallHandler(
                [](const flutter::MethodCall<>& call,
            std::unique_ptr<flutter::MethodResult<>> result) {
    
                    // check method name called from dart
                    if (call.method_name().compare("test") == 0) {
                    // do what ever you want
                    flutter::EncodableValue res;
                    res = flutter::EncodableValue("pass result here");
                    result->Success(res);
                    }
                    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());
      initMethodChannel(flutter_controller_->engine());
      SetChildContent(flutter_controller_->view()->GetNativeWindow());
    
      flutter_controller_->engine()->SetNextFrameCallback([&]() {
        this->Show();
      });
    
      return true;
    }
    
    void FlutterWindow::OnDestroy() {
      if (flutter_controller_) {
        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 opportunity 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);
    }
    

    Happy coding!