[windows] Expose the binary messenger from FlutterEngine (flutter/engine#20551)

Relands https://github.com/flutter/engine/pull/20399

Makes BinaryMessenger available from FlutterEngine, rather than just the plugin registrar. This allows for method channels directly in applications without building them as plugins, and matches the other platforms.

Requires some restructuring of code and GN targets in the client wrappers to make the internals in the shared section usable by the implementations of platform-specific parts of the wrappers. Also fixes a latent issue with EnableInputBlocking symbols being declared but not defined for Windows that came up during testing of the restructing.

Fixes https://github.com/flutter/flutter/issues/62871
This commit is contained in:
stuartmorgan 2020-08-17 05:44:48 -07:00 committed by GitHub
parent 869428afe5
commit 67cf6c312c
24 changed files with 316 additions and 194 deletions

View File

@ -836,7 +836,9 @@ FILE: ../../../flutter/shell/platform/android/surface/android_surface_mock.h
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.cc
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/basic_message_channel_unittests.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/binary_messenger_impl.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/byte_buffer_streams.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/core_implementations.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/encodable_value_unittests.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/engine_method_result.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/event_channel_unittests.cc

View File

@ -8,7 +8,8 @@ import("core_wrapper_files.gni")
# Client library build for internal use by the shell implementation.
source_set("client_wrapper") {
sources = core_cpp_client_wrapper_sources
public = core_cpp_client_wrapper_includes
public = core_cpp_client_wrapper_includes +
core_cpp_client_wrapper_internal_headers
deps = [ "//flutter/shell/platform/common/cpp:common_cpp_library_headers" ]
@ -23,7 +24,8 @@ source_set("client_wrapper") {
# legacy version is removed.
source_set("client_wrapper_legacy_encodable_value") {
sources = core_cpp_client_wrapper_sources
public = core_cpp_client_wrapper_includes
public = core_cpp_client_wrapper_includes +
core_cpp_client_wrapper_internal_headers
deps = [ "//flutter/shell/platform/common/cpp:common_cpp_library_headers" ]

View File

@ -0,0 +1,50 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_
#include <flutter_messenger.h>
#include <map>
#include <string>
#include "include/flutter/binary_messenger.h"
namespace flutter {
// Wrapper around a FlutterDesktopMessengerRef that implements the
// BinaryMessenger API.
class BinaryMessengerImpl : public BinaryMessenger {
public:
explicit BinaryMessengerImpl(FlutterDesktopMessengerRef core_messenger);
virtual ~BinaryMessengerImpl();
// Prevent copying.
BinaryMessengerImpl(BinaryMessengerImpl const&) = delete;
BinaryMessengerImpl& operator=(BinaryMessengerImpl const&) = delete;
// |flutter::BinaryMessenger|
void Send(const std::string& channel,
const uint8_t* message,
size_t message_size,
BinaryReply reply) const override;
// |flutter::BinaryMessenger|
void SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) override;
private:
// Handle for interacting with the C API.
FlutterDesktopMessengerRef messenger_;
// A map from channel names to the BinaryMessageHandler that should be called
// for incoming messages on that channel.
std::map<std::string, BinaryMessageHandler> handlers_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_

View File

@ -0,0 +1,150 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains the implementations of any class in the wrapper that
// - is not fully inline, and
// - is necessary for all clients of the wrapper (either app or plugin).
// It exists instead of the usual structure of having some_class_name.cc files
// so that changes to the set of things that need non-header implementations
// are not breaking changes for the template.
//
// If https://github.com/flutter/flutter/issues/57146 is fixed, this can be
// removed in favor of the normal structure since templates will no longer
// manually include files.
#include <assert.h>
#include <iostream>
#include "binary_messenger_impl.h"
#include "include/flutter/engine_method_result.h"
namespace flutter {
// ========== binary_messenger_impl.h ==========
namespace {
// Passes |message| to |user_data|, which must be a BinaryMessageHandler, along
// with a BinaryReply that will send a response on |message|'s response handle.
//
// This serves as an adaptor between the function-pointer-based message callback
// interface provided by the C API and the std::function-based message handler
// interface of BinaryMessenger.
void ForwardToHandler(FlutterDesktopMessengerRef messenger,
const FlutterDesktopMessage* message,
void* user_data) {
auto* response_handle = message->response_handle;
BinaryReply reply_handler = [messenger, response_handle](
const uint8_t* reply,
size_t reply_size) mutable {
if (!response_handle) {
std::cerr << "Error: Response can be set only once. Ignoring "
"duplicate response."
<< std::endl;
return;
}
FlutterDesktopMessengerSendResponse(messenger, response_handle, reply,
reply_size);
// The engine frees the response handle once
// FlutterDesktopSendMessageResponse is called.
response_handle = nullptr;
};
const BinaryMessageHandler& message_handler =
*static_cast<BinaryMessageHandler*>(user_data);
message_handler(message->message, message->message_size,
std::move(reply_handler));
}
} // namespace
BinaryMessengerImpl::BinaryMessengerImpl(
FlutterDesktopMessengerRef core_messenger)
: messenger_(core_messenger) {}
BinaryMessengerImpl::~BinaryMessengerImpl() = default;
void BinaryMessengerImpl::Send(const std::string& channel,
const uint8_t* message,
size_t message_size,
BinaryReply reply) const {
if (reply == nullptr) {
FlutterDesktopMessengerSend(messenger_, channel.c_str(), message,
message_size);
return;
}
struct Captures {
BinaryReply reply;
};
auto captures = new Captures();
captures->reply = reply;
auto message_reply = [](const uint8_t* data, size_t data_size,
void* user_data) {
auto captures = reinterpret_cast<Captures*>(user_data);
captures->reply(data, data_size);
delete captures;
};
bool result = FlutterDesktopMessengerSendWithReply(
messenger_, channel.c_str(), message, message_size, message_reply,
captures);
if (!result) {
delete captures;
}
}
void BinaryMessengerImpl::SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) {
if (!handler) {
handlers_.erase(channel);
FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(), nullptr,
nullptr);
return;
}
// Save the handler, to keep it alive.
handlers_[channel] = std::move(handler);
BinaryMessageHandler* message_handler = &handlers_[channel];
// Set an adaptor callback that will invoke the handler.
FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(),
ForwardToHandler, message_handler);
}
// ========== engine_method_result.h ==========
namespace internal {
ReplyManager::ReplyManager(BinaryReply reply_handler)
: reply_handler_(std::move(reply_handler)) {
assert(reply_handler_);
}
ReplyManager::~ReplyManager() {
if (reply_handler_) {
// Warn, rather than send a not-implemented response, since the engine may
// no longer be valid at this point.
std::cerr
<< "Warning: Failed to respond to a message. This is a memory leak."
<< std::endl;
}
}
void ReplyManager::SendResponseData(const std::vector<uint8_t>* data) {
if (!reply_handler_) {
std::cerr
<< "Error: Only one of Success, Error, or NotImplemented can be "
"called,"
<< " and it can be called exactly once. Ignoring duplicate result."
<< std::endl;
return;
}
const uint8_t* message = data && !data->empty() ? data->data() : nullptr;
size_t message_size = data ? data->size() : 0;
reply_handler_(message, message_size);
reply_handler_ = nullptr;
}
} // namespace internal
} // namespace flutter

View File

@ -27,13 +27,26 @@ core_cpp_client_wrapper_includes =
],
"abspath")
# Headers that aren't public for clients of the wrapper, but are considered
# public for the purpose of BUILD dependencies (e.g., to allow
# windows/client_wrapper implementation files to include them).
core_cpp_client_wrapper_internal_headers =
get_path_info([
"binary_messenger_impl.h",
"byte_buffer_streams.h",
],
"abspath")
# TODO: Once the wrapper API is more stable, consolidate to as few files as is
# reasonable (without forcing different kinds of clients to take unnecessary
# code) to simplify use.
core_cpp_client_wrapper_sources = get_path_info([
"byte_buffer_streams.h",
"engine_method_result.cc",
"core_implementations.cc",
"plugin_registrar.cc",
"standard_codec.cc",
],
"abspath")
# Temporary shim, published for backwards compatibility.
# See comment in the file for more detail.
temporary_shim_files = get_path_info([ "engine_method_result.cc" ], "abspath")

View File

@ -2,44 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "include/flutter/engine_method_result.h"
// This file is deprecated in favor of core_implementations.cc. This is a
// temporary forwarding implementation so that the switch to
// core_implementations.cc isn't an immediate breaking change, allowing for the
// template to be updated to include it and update the template version before
// removing this file.
#include <assert.h>
#include <iostream>
namespace flutter {
namespace internal {
ReplyManager::ReplyManager(BinaryReply reply_handler)
: reply_handler_(std::move(reply_handler)) {
assert(reply_handler_);
}
ReplyManager::~ReplyManager() {
if (reply_handler_) {
// Warn, rather than send a not-implemented response, since the engine may
// no longer be valid at this point.
std::cerr
<< "Warning: Failed to respond to a message. This is a memory leak."
<< std::endl;
}
}
void ReplyManager::SendResponseData(const std::vector<uint8_t>* data) {
if (!reply_handler_) {
std::cerr
<< "Error: Only one of Success, Error, or NotImplemented can be "
"called,"
<< " and it can be called exactly once. Ignoring duplicate result."
<< std::endl;
return;
}
const uint8_t* message = data && !data->empty() ? data->data() : nullptr;
size_t message_size = data ? data->size() : 0;
reply_handler_(message, message_size);
reply_handler_ = nullptr;
}
} // namespace internal
} // namespace flutter
#include "core_implementations.cc"

View File

@ -7,125 +7,12 @@
#include <iostream>
#include <map>
#include "binary_messenger_impl.h"
#include "include/flutter/engine_method_result.h"
#include "include/flutter/method_channel.h"
namespace flutter {
namespace {
// Passes |message| to |user_data|, which must be a BinaryMessageHandler, along
// with a BinaryReply that will send a response on |message|'s response handle.
//
// This serves as an adaptor between the function-pointer-based message callback
// interface provided by the C API and the std::function-based message handler
// interface of BinaryMessenger.
void ForwardToHandler(FlutterDesktopMessengerRef messenger,
const FlutterDesktopMessage* message,
void* user_data) {
auto* response_handle = message->response_handle;
BinaryReply reply_handler = [messenger, response_handle](
const uint8_t* reply,
size_t reply_size) mutable {
if (!response_handle) {
std::cerr << "Error: Response can be set only once. Ignoring "
"duplicate response."
<< std::endl;
return;
}
FlutterDesktopMessengerSendResponse(messenger, response_handle, reply,
reply_size);
// The engine frees the response handle once
// FlutterDesktopSendMessageResponse is called.
response_handle = nullptr;
};
const BinaryMessageHandler& message_handler =
*static_cast<BinaryMessageHandler*>(user_data);
message_handler(message->message, message->message_size,
std::move(reply_handler));
}
} // namespace
// Wrapper around a FlutterDesktopMessengerRef that implements the
// BinaryMessenger API.
class BinaryMessengerImpl : public BinaryMessenger {
public:
explicit BinaryMessengerImpl(FlutterDesktopMessengerRef core_messenger)
: messenger_(core_messenger) {}
virtual ~BinaryMessengerImpl() = default;
// Prevent copying.
BinaryMessengerImpl(BinaryMessengerImpl const&) = delete;
BinaryMessengerImpl& operator=(BinaryMessengerImpl const&) = delete;
// |flutter::BinaryMessenger|
void Send(const std::string& channel,
const uint8_t* message,
size_t message_size,
BinaryReply reply) const override;
// |flutter::BinaryMessenger|
void SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) override;
private:
// Handle for interacting with the C API.
FlutterDesktopMessengerRef messenger_;
// A map from channel names to the BinaryMessageHandler that should be called
// for incoming messages on that channel.
std::map<std::string, BinaryMessageHandler> handlers_;
};
void BinaryMessengerImpl::Send(const std::string& channel,
const uint8_t* message,
size_t message_size,
BinaryReply reply) const {
if (reply == nullptr) {
FlutterDesktopMessengerSend(messenger_, channel.c_str(), message,
message_size);
return;
}
struct Captures {
BinaryReply reply;
};
auto captures = new Captures();
captures->reply = reply;
auto message_reply = [](const uint8_t* data, size_t data_size,
void* user_data) {
auto captures = reinterpret_cast<Captures*>(user_data);
captures->reply(data, data_size);
delete captures;
};
bool result = FlutterDesktopMessengerSendWithReply(
messenger_, channel.c_str(), message, message_size, message_reply,
captures);
if (!result) {
delete captures;
}
}
void BinaryMessengerImpl::SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) {
if (!handler) {
handlers_.erase(channel);
FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(), nullptr,
nullptr);
return;
}
// Save the handler, to keep it alive.
handlers_[channel] = std::move(handler);
BinaryMessageHandler* message_handler = &handlers_[channel];
// Set an adaptor callback that will invoke the handler.
FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(),
ForwardToHandler, message_handler);
}
// ===== PluginRegistrar =====
PluginRegistrar::PluginRegistrar(FlutterDesktopPluginRegistrarRef registrar)

View File

@ -71,7 +71,9 @@ template("publish_client_wrapper_core") {
"visibility",
])
public = core_cpp_client_wrapper_includes
sources = core_cpp_client_wrapper_sources + [ _wrapper_readme ]
sources = core_cpp_client_wrapper_sources +
core_cpp_client_wrapper_internal_headers + [ _wrapper_readme ] +
temporary_shim_files
}
}

View File

@ -52,14 +52,6 @@ void FlutterDesktopRegistrarSetDestructionHandler(
}
}
void FlutterDesktopRegistrarEnableInputBlocking(
FlutterDesktopPluginRegistrarRef registrar,
const char* channel) {
if (s_stub_implementation) {
s_stub_implementation->RegistrarEnableInputBlocking(channel);
}
}
bool FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger,
const char* channel,
const uint8_t* message,

View File

@ -38,9 +38,6 @@ class StubFlutterApi {
virtual void RegistrarSetDestructionHandler(
FlutterDesktopOnRegistrarDestroyed callback) {}
// Called for FlutterDesktopRegistrarEnableInputBlocking.
virtual void RegistrarEnableInputBlocking(const char* channel) {}
// Called for FlutterDesktopMessengerSend.
virtual bool MessengerSend(const char* channel,
const uint8_t* message,

View File

@ -31,19 +31,6 @@ FLUTTER_EXPORT void FlutterDesktopRegistrarSetDestructionHandler(
FlutterDesktopPluginRegistrarRef registrar,
FlutterDesktopOnRegistrarDestroyed callback);
// Enables input blocking on the given channel.
//
// If set, then the Flutter window will disable input callbacks
// while waiting for the handler for messages on that channel to run. This is
// useful if handling the message involves showing a modal window, for instance.
//
// This must be called after FlutterDesktopSetMessageHandler, as setting a
// handler on a channel will reset the input blocking state back to the
// default of disabled.
FLUTTER_EXPORT void FlutterDesktopRegistrarEnableInputBlocking(
FlutterDesktopPluginRegistrarRef registrar,
const char* channel);
#if defined(__cplusplus)
} // extern "C"
#endif

View File

@ -182,3 +182,11 @@ FlutterDesktopPluginRegistrarRef FlutterDesktopGetPluginRegistrar(
// The stub ignores this, so just return an arbitrary non-zero value.
return reinterpret_cast<FlutterDesktopPluginRegistrarRef>(2);
}
void FlutterDesktopRegistrarEnableInputBlocking(
FlutterDesktopPluginRegistrarRef registrar,
const char* channel) {
if (s_stub_implementation) {
s_stub_implementation->RegistrarEnableInputBlocking(channel);
}
}

View File

@ -88,6 +88,9 @@ class StubFlutterGlfwApi {
// Called for FlutterDesktopShutDownEngine.
virtual bool ShutDownEngine() { return true; }
// Called for FlutterDesktopRegistrarEnableInputBlocking.
virtual void RegistrarEnableInputBlocking(const char* channel) {}
};
// A test helper that owns a stub implementation, making it the test stub for

View File

@ -219,10 +219,26 @@ FLUTTER_EXPORT bool FlutterDesktopShutDownEngine(
FlutterDesktopEngineRef engine);
// Returns the window associated with this registrar's engine instance.
//
// This is a GLFW shell-specific extension to flutter_plugin_registrar.h
FLUTTER_EXPORT FlutterDesktopWindowRef
FlutterDesktopRegistrarGetWindow(FlutterDesktopPluginRegistrarRef registrar);
// Enables input blocking on the given channel.
//
// If set, then the Flutter window will disable input callbacks
// while waiting for the handler for messages on that channel to run. This is
// useful if handling the message involves showing a modal window, for instance.
//
// This must be called after FlutterDesktopSetMessageHandler, as setting a
// handler on a channel will reset the input blocking state back to the
// default of disabled.
//
// This is a GLFW shell-specific extension to flutter_plugin_registrar.h
FLUTTER_EXPORT void FlutterDesktopRegistrarEnableInputBlocking(
FlutterDesktopPluginRegistrarRef registrar,
const char* channel);
#if defined(__cplusplus)
} // extern "C"
#endif

View File

@ -20,10 +20,12 @@ _wrapper_sources = [
# This code will be merged into .../common/cpp/client_wrapper for client use,
# so uses header paths that assume the merged state. Include the header
# header directory of the core wrapper files so these includes will work.
# directories of the core wrapper files so these includes will work.
config("relative_core_wrapper_headers") {
include_dirs =
[ "//flutter/shell/platform/common/cpp/client_wrapper/include/flutter" ]
include_dirs = [
"//flutter/shell/platform/common/cpp/client_wrapper",
"//flutter/shell/platform/common/cpp/client_wrapper/include/flutter",
]
}
# Windows client wrapper build for internal use by the shell implementation.

View File

@ -7,6 +7,8 @@
#include <algorithm>
#include <iostream>
#include "binary_messenger_impl.h"
namespace flutter {
FlutterEngine::FlutterEngine(const DartProject& project) {
@ -25,6 +27,9 @@ FlutterEngine::FlutterEngine(const DartProject& project) {
}
engine_ = FlutterDesktopEngineCreate(c_engine_properties);
auto core_messenger = FlutterDesktopEngineGetMessenger(engine_);
messenger_ = std::make_unique<BinaryMessengerImpl>(core_messenger);
}
FlutterEngine::~FlutterEngine() {

View File

@ -93,4 +93,14 @@ TEST(FlutterEngineTest, ProcessMessages) {
EXPECT_EQ(next_event_time.count(), 99);
}
TEST(FlutterEngineTest, GetMessenger) {
DartProject project(L"data");
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
std::make_unique<TestFlutterWindowsApi>());
auto test_api = static_cast<TestFlutterWindowsApi*>(scoped_api_stub.stub());
FlutterEngine engine(DartProject(L"fake/project/path"));
EXPECT_NE(engine.messenger(), nullptr);
}
} // namespace flutter

View File

@ -12,6 +12,7 @@
#include <memory>
#include <string>
#include "binary_messenger.h"
#include "dart_project.h"
#include "plugin_registrar.h"
#include "plugin_registry.h"
@ -57,6 +58,12 @@ class FlutterEngine : public PluginRegistry {
FlutterDesktopPluginRegistrarRef GetRegistrarForPlugin(
const std::string& plugin_name) override;
// Returns the messenger to use for creating channels to communicate with the
// Flutter engine.
//
// This pointer will remain valid for the lifetime of this instance.
BinaryMessenger* messenger() { return messenger_.get(); }
private:
// For access to RelinquishEngine.
friend class FlutterViewController;
@ -70,6 +77,9 @@ class FlutterEngine : public PluginRegistry {
// Handle for interacting with the C API's engine reference.
FlutterDesktopEngineRef engine_ = nullptr;
// Messenger for communicating with the engine.
std::unique_ptr<BinaryMessenger> messenger_;
// Whether or not this wrapper owns |engine_|.
bool owns_engine_ = true;

View File

@ -101,6 +101,12 @@ FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar(
return reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1);
}
FlutterDesktopMessengerRef FlutterDesktopEngineGetMessenger(
FlutterDesktopEngineRef engine) {
// The stub ignores this, so just return an arbitrary non-zero value.
return reinterpret_cast<FlutterDesktopMessengerRef>(2);
}
HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef controller) {
if (s_stub_implementation) {
return s_stub_implementation->ViewGetHWND();

View File

@ -119,6 +119,11 @@ FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar(
return EngineFromHandle(engine)->GetRegistrar();
}
FlutterDesktopMessengerRef FlutterDesktopEngineGetMessenger(
FlutterDesktopEngineRef engine) {
return EngineFromHandle(engine)->messenger();
}
HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view_ref) {
return std::get<HWND>(*view_ref->view->GetRenderTarget());
}
@ -151,7 +156,7 @@ void FlutterDesktopResyncOutputStreams() {
FlutterDesktopMessengerRef FlutterDesktopRegistrarGetMessenger(
FlutterDesktopPluginRegistrarRef registrar) {
return registrar->messenger.get();
return registrar->messenger;
}
void FlutterDesktopRegistrarSetDestructionHandler(

View File

@ -85,15 +85,15 @@ FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project)
}
});
// Set up the structure of the state/handle objects; engine and view paramater
// will be filled in late.
auto messenger = std::make_unique<FlutterDesktopMessenger>();
// Set up the structure of the state/handle objects; engine and view
// paramaters will be filled in later.
messenger_ = std::make_unique<FlutterDesktopMessenger>();
message_dispatcher_ =
std::make_unique<IncomingMessageDispatcher>(messenger.get());
messenger->dispatcher = message_dispatcher_.get();
std::make_unique<IncomingMessageDispatcher>(messenger_.get());
messenger_->dispatcher = message_dispatcher_.get();
plugin_registrar_ = std::make_unique<FlutterDesktopPluginRegistrar>();
plugin_registrar_->messenger = std::move(messenger);
plugin_registrar_->messenger = messenger_.get();
plugin_registrar_->view = std::make_unique<FlutterDesktopView>();
}

View File

@ -60,6 +60,8 @@ class FlutterWindowsEngine {
FLUTTER_API_SYMBOL(FlutterEngine) engine() { return engine_; }
FlutterDesktopMessengerRef messenger() { return messenger_.get(); }
Win32TaskRunner* task_runner() { return task_runner_.get(); }
// Callback passed to Flutter engine for notifying window of platform
@ -81,6 +83,9 @@ class FlutterWindowsEngine {
// Task runner for tasks posted from the engine.
std::unique_ptr<Win32TaskRunner> task_runner_;
// The plugin messenger handle given to API clients.
std::unique_ptr<FlutterDesktopMessenger> messenger_;
// Message dispatch manager for messages from engine_.
std::unique_ptr<IncomingMessageDispatcher> message_dispatcher_;

View File

@ -136,6 +136,10 @@ FLUTTER_EXPORT FlutterDesktopPluginRegistrarRef
FlutterDesktopEngineGetPluginRegistrar(FlutterDesktopEngineRef engine,
const char* plugin_name);
// Returns the messenger associated with the engine.
FLUTTER_EXPORT FlutterDesktopMessengerRef
FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine);
// ========== View ==========
// Return backing HWND for manipulation in host application.

View File

@ -35,7 +35,7 @@ struct FlutterDesktopView {
// State associated with the plugin registrar.
struct FlutterDesktopPluginRegistrar {
// The plugin messenger handle given to API clients.
std::unique_ptr<FlutterDesktopMessenger> messenger;
FlutterDesktopMessenger* messenger;
// The handle for the view associated with this registrar.
std::unique_ptr<FlutterDesktopView> view;