未验证 提交 3ebcde6a 编写于 作者: S stuartmorgan 提交者: GitHub

Revert "[windows] Expose the binary messenger from FlutterEngine (#20399)" (#20550)

This reverts commit 7fa21a45.
上级 7fa21a45
......@@ -836,9 +836,7 @@ 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
......
......@@ -8,8 +8,7 @@ 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 +
core_cpp_client_wrapper_internal_headers
public = core_cpp_client_wrapper_includes
deps = [ "//flutter/shell/platform/common/cpp:common_cpp_library_headers" ]
......
// 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_
// 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
......@@ -27,26 +27,13 @@ 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([
"core_implementations.cc",
"byte_buffer_streams.h",
"engine_method_result.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")
......@@ -2,10 +2,44 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// 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 "include/flutter/engine_method_result.h"
#include "core_implementations.cc"
#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
......@@ -7,12 +7,125 @@
#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)
......
......@@ -71,9 +71,7 @@ template("publish_client_wrapper_core") {
"visibility",
])
public = core_cpp_client_wrapper_includes
sources = core_cpp_client_wrapper_sources +
core_cpp_client_wrapper_internal_headers + [ _wrapper_readme ] +
temporary_shim_files
sources = core_cpp_client_wrapper_sources + [ _wrapper_readme ]
}
}
......
......@@ -52,6 +52,14 @@ 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,
......
......@@ -38,6 +38,9 @@ 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,
......
......@@ -31,6 +31,19 @@ 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
......
......@@ -182,11 +182,3 @@ 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);
}
}
......@@ -88,9 +88,6 @@ 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
......
......@@ -219,26 +219,10 @@ 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
......
......@@ -20,12 +20,10 @@ _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
# directories of the core wrapper files so these includes will work.
# header directory of the core wrapper files so these includes will work.
config("relative_core_wrapper_headers") {
include_dirs = [
"//flutter/shell/platform/common/cpp/client_wrapper",
"//flutter/shell/platform/common/cpp/client_wrapper/include/flutter",
]
include_dirs =
[ "//flutter/shell/platform/common/cpp/client_wrapper/include/flutter" ]
}
# Windows client wrapper build for internal use by the shell implementation.
......
......@@ -7,8 +7,6 @@
#include <algorithm>
#include <iostream>
#include "binary_messenger_impl.h"
namespace flutter {
FlutterEngine::FlutterEngine(const DartProject& project) {
......@@ -27,9 +25,6 @@ FlutterEngine::FlutterEngine(const DartProject& project) {
}
engine_ = FlutterDesktopEngineCreate(c_engine_properties);
auto core_messenger = FlutterDesktopEngineGetMessenger(engine_);
messenger_ = std::make_unique<BinaryMessengerImpl>(core_messenger);
}
FlutterEngine::~FlutterEngine() {
......
......@@ -93,14 +93,4 @@ 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
......@@ -12,7 +12,6 @@
#include <memory>
#include <string>
#include "binary_messenger.h"
#include "dart_project.h"
#include "plugin_registrar.h"
#include "plugin_registry.h"
......@@ -58,12 +57,6 @@ 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;
......@@ -77,9 +70,6 @@ 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;
......
......@@ -101,12 +101,6 @@ 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();
......
......@@ -119,11 +119,6 @@ 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());
}
......@@ -156,7 +151,7 @@ void FlutterDesktopResyncOutputStreams() {
FlutterDesktopMessengerRef FlutterDesktopRegistrarGetMessenger(
FlutterDesktopPluginRegistrarRef registrar) {
return registrar->messenger;
return registrar->messenger.get();
}
void FlutterDesktopRegistrarSetDestructionHandler(
......
......@@ -85,15 +85,15 @@ FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project)
}
});
// Set up the structure of the state/handle objects; engine and view
// paramaters will be filled in later.
messenger_ = std::make_unique<FlutterDesktopMessenger>();
// Set up the structure of the state/handle objects; engine and view paramater
// will be filled in late.
auto 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 = messenger_.get();
plugin_registrar_->messenger = std::move(messenger);
plugin_registrar_->view = std::make_unique<FlutterDesktopView>();
}
......
......@@ -60,8 +60,6 @@ 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
......@@ -83,9 +81,6 @@ 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_;
......
......@@ -136,10 +136,6 @@ 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.
......
......@@ -35,7 +35,7 @@ struct FlutterDesktopView {
// State associated with the plugin registrar.
struct FlutterDesktopPluginRegistrar {
// The plugin messenger handle given to API clients.
FlutterDesktopMessenger* messenger;
std::unique_ptr<FlutterDesktopMessenger> messenger;
// The handle for the view associated with this registrar.
std::unique_ptr<FlutterDesktopView> view;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册